package de.otto.flummi; import com.google.gson.Gson; import com.google.gson.JsonObject; import de.otto.flummi.aggregations.NestedAggregationBuilder; import de.otto.flummi.aggregations.TermsBuilder; import de.otto.flummi.query.QueryBuilders; import de.otto.flummi.request.SearchRequestBuilder; import de.otto.flummi.response.AggregationResult; import de.otto.flummi.response.ScrollingSearchHits; import de.otto.flummi.response.SearchHit; import de.otto.flummi.response.SearchResponse; import de.otto.flummi.util.HttpClientWrapper; import org.asynchttpclient.BoundRequestBuilder; import org.asynchttpclient.ListenableFuture; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.nio.charset.Charset; import java.util.concurrent.TimeoutException; import static de.otto.flummi.SortOrder.ASC; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.notNullValue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; public class SearchRequestBuilderTest { public static final String EMPTY_SEARCH_RESPONSE = "{\"took\":1, \"hits\":{\"max_score\":null,\"total\":0, \"hits\":[]}}"; public static final String PRODUCT_JSON = "{\"_id\":\"P0\",\"lastModified\":\"2016-04-14T09:17:46.888\",\"topProductScore\":0.0,\"promotable\":true,\"soldout\":false,\"sale\":false,\"largeSize\":false,\"premiumBrand\":false,\"sharedCategoryPath\":\"some\",\"brand\":\"adidas\",\"categories\":[{\"path\":\"some/path/p0/\",\"titlePath\":\"Some\\u003ePath\\u003eP0\",\"assortment\":\"spielzeug\",\"targetGroup\":\"herren\",\"uniqueId\":\"Some\\u003ePath\\u003eP0§spielzeug§herren\"},{\"path\":\"some/other/path/p0/\",\"titlePath\":\"Some\\u003eOther\\u003ePath\\u003eP0\",\"assortment\":\"sport\",\"targetGroup\":\"herren\",\"uniqueId\":\"Some\\u003eOther\\u003ePath\\u003eP0§sport§herren\"}],\"levelCategories\":{\"1\":{\"value\":[\"p0\",\"path\"],\"count\":2},\"2\":{\"value\":[\"p0\"],\"count\":1}},\"tags\":[],\"reductionClasses\":[],\"displayRestrictions\":[]}"; public static final String SEARCH_RESPONSE_WITH_ONE_HIT = "{\"took\":1," + "\"timed_out\":false," + "\"_shards\":{\"total\":5,\"successful\":5,\"failed\":0}," + "\"hits\":{\"total\":1,\"max_score\":1.0,\"hits\":[" + "{\"_index\":\"product_1460618266743\",\"_type\":\"product\",\"_id\":\"P0\",\"_score\":1.0,\"_source\":" + PRODUCT_JSON + "}" + "]}}"; public static final String SEARCH_RESPONSE_WITH_ONE_HIT_VERSION_7 = "{\"took\":1," + "\"timed_out\":false," + "\"_shards\":{\"total\":5,\"successful\":5,\"failed\":0}," + "\"hits\":{\"total\":{\"value\":1,\"relation\":\"eq\"},\"max_score\":1.0,\"hits\":[" + "{\"_index\":\"product_1460618266743\",\"_type\":\"product\",\"_id\":\"P0\",\"_score\":1.0,\"_source\":" + PRODUCT_JSON + "}" + "]}}"; public static final String SEARCH_RESPONSE_WITH_AGGREGATION = "{\"took\":85," + "\"timed_out\":false," + "\"_shards\":{\"total\":1,\"successful\":1,\"failed\":0}," + "\"hits\":{\"total\":2,\"max_score\":0.0,\"hits\":[]}," + "\"aggregations\":{" + "\"categories_distinct\":{" + "\"doc_count\":2," + "\"categories_unique_id_distinct\":{" + "\"doc_count_error_upper_bound\":0," + "\"sum_other_doc_count\":0," + "\"buckets\":[{\"key\":\"Spielzeug>Path>More§spielzeug§damen\",\"doc_count\":1},{\"key\":\"Spielzeug>Path§spielzeug§herren\",\"doc_count\":1}]}}}}"; public static final String SEARCH_RESPONSE_WITH_SCROLL_ID = "{\"took\":1," + "\"_scroll_id\":\"some_scroll_id\"," + "\"timed_out\":false," + "\"_shards\":{\"total\":5,\"successful\":5,\"failed\":0}," + "\"hits\":{\"total\":10,\"max_score\":1.0,\"hits\":[" + "{\"_index\":\"product_1460618266743\",\"_type\":\"product\",\"_id\":\"P0\",\"_score\":1.0,\"_source\":" + PRODUCT_JSON + "}," + "{\"_index\":\"product_1460618266743\",\"_type\":\"product\",\"_id\":\"P1\",\"_score\":1.0,\"_source\":" + PRODUCT_JSON + "}" + "]}}"; SearchRequestBuilder searchRequestBuilder; HttpClientWrapper httpClient; @BeforeMethod public void setUp() throws Exception { httpClient = mock(HttpClientWrapper.class); searchRequestBuilder = new SearchRequestBuilder(httpClient, "some-index"); } @Test public void shouldBuilderQueryWithStoredField() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", EMPTY_SEARCH_RESPONSE))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).addStoredField("someField").execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}},\"stored_fields\":[\"someField\"]}"); verify(httpClient).preparePost("/some-index/_search"); } @Test public void shouldBuilderQueryWithSourceFilter() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", EMPTY_SEARCH_RESPONSE))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).addSourceFilter("someField").execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}},\"_source\":[\"someField\"]}"); verify(httpClient).preparePost("/some-index/_search"); } @Test public void shouldParseSearchResponseWithFullDocuments() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", SEARCH_RESPONSE_WITH_ONE_HIT))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}}}"); verify(httpClient).preparePost("/some-index/_search"); assertThat(response.getTookInMillis(), is(1L)); assertThat(response.getHits().getMaxScore(), is(1F)); assertThat(response.getAggregations().size(), is(0)); assertThat(response.getHits().getTotalHits(), is(1L)); SearchHit firstHit = response.getHits().iterator().next(); assertThat(firstHit.getFields().entrySet().size(), is(0)); assertThat(firstHit.getId(), is("P0")); assertThat(firstHit.getScore(), is(1F)); assertThat(firstHit.getSource(), is(new Gson().fromJson(PRODUCT_JSON, JsonObject.class))); } @Test public void shouldParseSearchResponseWithFullDocumentsForEsVersion7() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", SEARCH_RESPONSE_WITH_ONE_HIT_VERSION_7))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}}}"); verify(httpClient).preparePost("/some-index/_search"); assertThat(response.getTookInMillis(), is(1L)); assertThat(response.getHits().getMaxScore(), is(1F)); assertThat(response.getAggregations().size(), is(0)); assertThat(response.getHits().getTotalHits(), is(1L)); SearchHit firstHit = response.getHits().iterator().next(); assertThat(firstHit.getFields().entrySet().size(), is(0)); assertThat(firstHit.getId(), is("P0")); assertThat(firstHit.getScore(), is(1F)); assertThat(firstHit.getSource(), is(new Gson().fromJson(PRODUCT_JSON, JsonObject.class))); } @Test public void shouldParseSearchResponseWithAggregations() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", SEARCH_RESPONSE_WITH_AGGREGATION))); // when SearchResponse response = searchRequestBuilder .addAggregation( new NestedAggregationBuilder("categories_distinct") .path("categories") .subAggregation( new TermsBuilder("categories_unique_id_distinct") .field("categories.uniqueId") .size(10) )) .setQuery(createSampleQuery()).execute(); //then verify(httpClient).preparePost("/some-index/_search"); assertThat(response.getAggregations().size(), is(1)); AggregationResult categoriesAggregation = response.getAggregations().get("categories_distinct"); assertThat(categoriesAggregation.getNestedAggregations().get("categories_unique_id_distinct").getBuckets(), hasSize(2)); } @Test public void shouldBuilderQueryWithFromAndSize() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", EMPTY_SEARCH_RESPONSE))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).setSize(42).setFrom(111).execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}},\"from\":111,\"size\":42}"); verify(httpClient).preparePost("/some-index/_search"); } @Test public void shouldSetHttpRequestTimeout() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", EMPTY_SEARCH_RESPONSE))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).setTimeoutMillis(54321).execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}}}"); verify(boundRequestBuilderMock).setRequestTimeout(54321); verify(httpClient).preparePost("/some-index/_search"); } @Test public void shouldBuildRequestWithOneSort() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", EMPTY_SEARCH_RESPONSE))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).addSort("someKey", SortOrder.DESC).execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}},\"sort\":[{\"someKey\":{\"order\":\"desc\"}}]}"); verify(httpClient).preparePost("/some-index/_search"); } @Test public void shouldBuildRequestWithMultipleSort() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", EMPTY_SEARCH_RESPONSE))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).addSort("someKey", SortOrder.DESC).addSort("someOtherKey", ASC).execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}},\"sort\":[{\"someKey\":{\"order\":\"desc\"}},{\"someOtherKey\":{\"order\":\"asc\"}}]}"); verify(httpClient).preparePost("/some-index/_search"); } @Test public void shouldBuildRequestWithPostFilter() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", EMPTY_SEARCH_RESPONSE))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).setPostFilter(QueryBuilders.termQuery("someField", "someValue")).execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}},\"post_filter\":{\"term\":{\"someField\":\"someValue\"}}}"); verify(httpClient).preparePost("/some-index/_search"); } @Test public void shouldBuildRequestWithAggregations() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", EMPTY_SEARCH_RESPONSE))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()).addAggregation(new TermsBuilder("Katzenklo") .field("someField")) .execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}}," + "\"aggregations\":{\"Katzenklo\":{\"terms\":{\"field\":\"someField\"}}}}"); verify(httpClient).preparePost("/some-index/_search"); } @Test public void shouldBuildRequestWithScroll() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", SEARCH_RESPONSE_WITH_SCROLL_ID))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()) .setScroll("1m") .execute(); //then verify(boundRequestBuilderMock).setBody("{\"query\":{\"term\":{\"someField\":\"someValue\"}}}"); verify(httpClient).preparePost("/some-index/_search"); verify(boundRequestBuilderMock).addQueryParam("scroll", "1m"); assertThat(response.getScrollId(), is("some_scroll_id")); } @Test public void shouldBuildRequestWithNestedAggregations() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", EMPTY_SEARCH_RESPONSE))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()) .addAggregation(new NestedAggregationBuilder("Katzenklo") .path("somePath") .subAggregation(new TermsBuilder("someAggregation").field("someField")) ) .execute(); //then verify(boundRequestBuilderMock).setBody( "{" + "\"query\":{\"term\":{\"someField\":\"someValue\"}}," + "\"aggregations\":{" + "\"Katzenklo\":{" + "\"nested\":{\"path\":\"somePath\"}," + "\"aggregations\":{" + "\"someAggregation\":{" + "\"terms\":{\"field\":\"someField\"}" + "}" + "}" + "}" + "}" + "}"); verify(httpClient).preparePost("/some-index/_search"); } @Test public void shouldScroll() throws Exception { // given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.execute()).thenReturn(new CompletedFuture<>(new MockResponse(200, "ok", SEARCH_RESPONSE_WITH_SCROLL_ID))); // when SearchResponse response = searchRequestBuilder.setQuery(createSampleQuery()) .setScroll("1m") .execute(); //then assertThat(response.getHits().getClass().getName(), is(ScrollingSearchHits.class.getName())); } @Test public void shouldNotThrowNPExceptionIfScrollIdIsNotInSearchResponse() throws Exception { Gson gson = new Gson(); JsonObject jsonResponse = gson.fromJson("{\"took\":3,\"timed_out\":false,\"_shards\":{\"total\":5,\"successful\":5,\"failed\":0},\"hits\":{\"total\":2,\"max_score\":1.0,\"hits\":[{\"_index\":\"salesorders\",\"_type\":\"salesorders\",\"_id\":\"AVoUU6q__Si-JRVFBPXC\",\"_score\":1.0,\"_source\":{\"quoteNumber\":\"11111111111\",\"quoteReference\":\"blablabla\",\"postCode\":\"RH41EA\"}},{\"_index\":\"salesorders\",\"_type\":\"salesorders\",\"_id\":\"AVoUU764_Si-JRVFBPXD\",\"_score\":1.0,\"_source\":{\"quoteNumber\":\"11111111111\",\"quoteReference\":\"blablabla\",\"postCode\":\"RH41EA\"}}]}}", JsonObject.class); SearchResponse.Builder response = searchRequestBuilder.parseResponse(jsonResponse, "1m", null); assertThat(response, is(notNullValue())); } @Test public void shouldAddQueryToException() throws Exception { //given BoundRequestBuilder boundRequestBuilderMock = mock(BoundRequestBuilder.class); when(httpClient.preparePost("/some-index/_search")).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setBody(any(String.class))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.setCharset(Charset.forName("UTF-8"))).thenReturn(boundRequestBuilderMock); when(boundRequestBuilderMock.addHeader(anyString(),anyString())).thenReturn(boundRequestBuilderMock); TimeoutException timeoutException = new TimeoutException(); when(boundRequestBuilderMock.execute()).thenReturn(new ListenableFuture.CompletedFailure<>(timeoutException)); //when JsonObject query = createSampleQuery(); try { searchRequestBuilder.setQuery(query).execute(); } catch (RuntimeException e) { //then assertThat(e.getCause().getCause(), is(timeoutException)); assertThat(e.getMessage(), is("{\"query\":" + query.toString() + "}")); } } private JsonObject createSampleQuery() { return QueryBuilders.termQuery("someField", "someValue").build(); } }