org.finra.herd.dao.IndexSearchDaoTest.java Source code

Java tutorial

Introduction

Here is the source code for org.finra.herd.dao.IndexSearchDaoTest.java

Source

/*
* Copyright 2015 herd contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.finra.herd.dao;

import static org.finra.herd.dao.helper.ElasticsearchHelper.DISPLAY_NAME_SOURCE;
import static org.finra.herd.dao.helper.ElasticsearchHelper.TAG_TYPE_FACET_AGGS;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import io.searchbox.core.SearchResult;
import io.searchbox.core.search.aggregation.MetricAggregation;
import io.searchbox.core.search.aggregation.TermsAggregation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.ListenableActionFuture;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.SearchShardTarget;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilder;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.finra.herd.core.helper.ConfigurationHelper;
import org.finra.herd.dao.helper.ElasticsearchHelper;
import org.finra.herd.dao.helper.HerdSearchQueryHelper;
import org.finra.herd.dao.helper.JestClientHelper;
import org.finra.herd.dao.helper.JsonHelper;
import org.finra.herd.dao.impl.IndexSearchDaoImpl;
import org.finra.herd.model.api.xml.IndexSearchFilter;
import org.finra.herd.model.api.xml.IndexSearchKey;
import org.finra.herd.model.api.xml.IndexSearchRequest;
import org.finra.herd.model.api.xml.IndexSearchResponse;
import org.finra.herd.model.api.xml.IndexSearchResult;
import org.finra.herd.model.api.xml.IndexSearchResultTypeKey;
import org.finra.herd.model.api.xml.TagKey;
import org.finra.herd.model.dto.ConfigurationValue;
import org.finra.herd.model.dto.ElasticsearchResponseDto;
import org.finra.herd.model.dto.IndexSearchHighlightField;
import org.finra.herd.model.dto.IndexSearchHighlightFields;
import org.finra.herd.model.dto.ResultTypeIndexSearchResponseDto;
import org.finra.herd.model.dto.TagIndexSearchResponseDto;
import org.finra.herd.model.dto.TagTypeIndexSearchResponseDto;
import org.finra.herd.model.jpa.SearchIndexTypeEntity;

/**
 * IndexSearchDaoTest
 */
public class IndexSearchDaoTest extends AbstractDaoTest {
    private static final String NAMESPACE = "namespace";

    private static final String TAG_TYPE = "tagType";

    @InjectMocks
    private IndexSearchDaoImpl indexSearchDao;

    @Mock
    private ConfigurationHelper configurationHelper;

    @Mock
    private ElasticsearchHelper elasticsearchHelper;

    @Mock
    private JestClientHelper jestClientHelper;

    @Mock
    private JsonHelper jsonHelper;

    @Mock
    private HerdSearchQueryHelper herdSearchQueryHelper;

    @Before
    public void before() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void indexSearchTest() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = Sets.newHashSet(DISPLAY_NAME_FIELD, SHORT_DESCRIPTION_FIELD);
        testIndexSearch(fields, null, null, NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithException() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = Sets.newHashSet(DISPLAY_NAME_FIELD, SHORT_DESCRIPTION_FIELD);
        testIndexSearch(SEARCH_TERM, fields, NO_MATCH, null, null, NO_ENABLE_HIT_HIGHLIGHTING, true, false,
                DISABLE_COLUMN_FIELDS);
    }

    @Test
    public void indexSearchTestWithExceptionWhenBuildingMultiMatchQueryWithBoosts() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = Sets.newHashSet(DISPLAY_NAME_FIELD, SHORT_DESCRIPTION_FIELD);
        testIndexSearch(SEARCH_TERM, fields, NO_MATCH, null, null, NO_ENABLE_HIT_HIGHLIGHTING, true, false,
                DISABLE_COLUMN_FIELDS);
    }

    @Test
    public void indexSearchTestWithExceptionWhenBuildingHighlightQuery() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = Sets.newHashSet(DISPLAY_NAME_FIELD, SHORT_DESCRIPTION_FIELD);
        testIndexSearch(SEARCH_TERM, fields, NO_MATCH, null, null, ENABLE_HIT_HIGHLIGHTING, true, false,
                DISABLE_COLUMN_FIELDS);
    }

    @Test
    public void indexSearchTestWithMatchWithColumnFields() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = Sets.newHashSet(DISPLAY_NAME_FIELD, SHORT_DESCRIPTION_FIELD);

        // Create a set of match fields.
        final Set<String> match = Sets.newHashSet(MATCH_COLUMN);

        testIndexSearch(SEARCH_TERM, fields, match, null, null, NO_ENABLE_HIT_HIGHLIGHTING, false, false,
                ENABLE_COLUMN_FIELDS);
    }

    @Test
    public void indexSearchTestWithMatchNoColumnFields() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = Sets.newHashSet(DISPLAY_NAME_FIELD, SHORT_DESCRIPTION_FIELD);

        // Create a set of match fields.
        final Set<String> match = Sets.newHashSet(MATCH_COLUMN);

        testIndexSearch(SEARCH_TERM, fields, match, null, null, NO_ENABLE_HIT_HIGHLIGHTING, false, false,
                DISABLE_COLUMN_FIELDS);
    }

    @Test
    public void indexSearchTestInvalidSearchResultIndexName() throws IOException {
        // Create a set of fields.
        final Set<String> fields = Sets.newHashSet(DISPLAY_NAME_FIELD, SHORT_DESCRIPTION_FIELD);

        // Try to call the method under test.
        try {
            testIndexSearch(SEARCH_TERM, fields, NO_MATCH, null, null, NO_ENABLE_HIT_HIGHLIGHTING, false, true,
                    DISABLE_COLUMN_FIELDS);
            fail();
        } catch (IllegalStateException e) {
            assertEquals("Unexpected response received when attempting to retrieve search results.",
                    e.getMessage());
        }

        // Verify external calls.
        verify(jsonHelper, times(2)).objectToJson(any());
    }

    @Test
    public void indexSearchTestWithNoFields() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();
        testIndexSearch(fields, null, null, NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithFacets() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();
        //tag and result set facet
        testIndexSearch(fields, null,
                Arrays.asList(ElasticsearchHelper.RESULT_TYPE_FACET, ElasticsearchHelper.TAG_FACET),
                NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithTagFacet() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        //tag facet only
        testIndexSearch(fields, null, Collections.singletonList(ElasticsearchHelper.TAG_FACET),
                NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithResultTypeFacet() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        //result type facet only
        testIndexSearch(fields, null, Collections.singletonList(ElasticsearchHelper.RESULT_TYPE_FACET),
                NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithEmptyFilters() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        // Create a new filters list
        List<IndexSearchFilter> searchFilters = new ArrayList<>();

        //result type facet only
        testIndexSearch(fields, searchFilters, null, NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithTagKeyFilter() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        // Create an index search key
        final IndexSearchKey indexSearchKey = new IndexSearchKey();

        // Create a tag key
        final TagKey tagKey = new TagKey(TAG_TYPE_CODE, TAG_CODE);
        indexSearchKey.setTagKey(tagKey);

        // Create an index search keys list and add the previously defined key to it
        final List<IndexSearchKey> indexSearchKeys = Collections.singletonList(indexSearchKey);

        // Create an index search filter with the keys previously defined
        final IndexSearchFilter indexSearchFilter = new IndexSearchFilter(NO_EXCLUSION_SEARCH_FILTER,
                indexSearchKeys);

        List<IndexSearchFilter> indexSearchFilters = Collections.singletonList(indexSearchFilter);

        //result type facet only
        testIndexSearch(fields, indexSearchFilters, null, NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithTagKeyFilterAndNoSearchTerm() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        // Create an index search key
        final IndexSearchKey indexSearchKey = new IndexSearchKey();

        // Create a tag key
        final TagKey tagKey = new TagKey(TAG_TYPE_CODE, TAG_CODE);
        indexSearchKey.setTagKey(tagKey);

        // Create an index search keys list and add the previously defined key to it
        final List<IndexSearchKey> indexSearchKeys = Collections.singletonList(indexSearchKey);

        // Create an index search filter with the keys previously defined
        final IndexSearchFilter indexSearchFilter = new IndexSearchFilter(NO_EXCLUSION_SEARCH_FILTER,
                indexSearchKeys);

        List<IndexSearchFilter> indexSearchFilters = Collections.singletonList(indexSearchFilter);

        //result type facet only
        testIndexSearch(null, fields, indexSearchFilters, null, NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithResultTypeFilter() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        // Create an index search key
        final IndexSearchKey indexSearchKey = new IndexSearchKey();

        // Create a result type key
        final IndexSearchResultTypeKey resultTypeKey = new IndexSearchResultTypeKey(
                SearchIndexTypeEntity.SearchIndexTypes.BUS_OBJCT_DFNTN.name());
        indexSearchKey.setIndexSearchResultTypeKey(resultTypeKey);

        // Create an index search keys list and add the previously defined key to it
        final List<IndexSearchKey> indexSearchKeys = Collections.singletonList(indexSearchKey);

        // Create an index search filter with the keys previously defined
        final IndexSearchFilter indexSearchFilter = new IndexSearchFilter(NO_EXCLUSION_SEARCH_FILTER,
                indexSearchKeys);

        List<IndexSearchFilter> indexSearchFilters = Collections.singletonList(indexSearchFilter);

        //result type facet only
        testIndexSearch(fields, indexSearchFilters, null, NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithTagKeyFilterAndExcludeFlagSet() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        // Create an index search key
        final IndexSearchKey indexSearchKey = new IndexSearchKey();

        // Create a tag key
        final TagKey tagKey = new TagKey(TAG_TYPE_CODE, TAG_CODE);
        indexSearchKey.setTagKey(tagKey);

        // Create an index search keys list and add the previously defined key to it
        final List<IndexSearchKey> indexSearchKeys = Collections.singletonList(indexSearchKey);

        // Create an index search filter with the keys previously defined
        final IndexSearchFilter indexSearchFilter = new IndexSearchFilter(NO_EXCLUSION_SEARCH_FILTER,
                indexSearchKeys);

        // Set exclude filter flag to true
        indexSearchFilter.setIsExclusionSearchFilter(true);

        List<IndexSearchFilter> indexSearchFilters = Collections.singletonList(indexSearchFilter);

        //result type facet only
        testIndexSearch(fields, indexSearchFilters, null, NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchTestWithResultTypeFilterAndExcludeFlagSet() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        // Create an index search key
        final IndexSearchKey indexSearchKey = new IndexSearchKey();

        // Create a result type key
        final IndexSearchResultTypeKey resultTypeKey = new IndexSearchResultTypeKey(
                SearchIndexTypeEntity.SearchIndexTypes.BUS_OBJCT_DFNTN.name());
        indexSearchKey.setIndexSearchResultTypeKey(resultTypeKey);

        // Create an index search keys list and add the previously defined key to it
        final List<IndexSearchKey> indexSearchKeys = Collections.singletonList(indexSearchKey);

        // Create an index search filter with the keys previously defined
        final IndexSearchFilter indexSearchFilter = new IndexSearchFilter(NO_EXCLUSION_SEARCH_FILTER,
                indexSearchKeys);

        // Set exclude flag to true
        indexSearchFilter.setIsExclusionSearchFilter(true);

        List<IndexSearchFilter> indexSearchFilters = Collections.singletonList(indexSearchFilter);

        //result type facet only
        testIndexSearch(fields, indexSearchFilters, null, NO_ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchWithResultTypeExcludeFilterAndHitHighlighting() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        // Create an index search key
        final IndexSearchKey indexSearchKey = new IndexSearchKey();

        // Create a result type key
        final IndexSearchResultTypeKey resultTypeKey = new IndexSearchResultTypeKey(
                SearchIndexTypeEntity.SearchIndexTypes.BUS_OBJCT_DFNTN.name());
        indexSearchKey.setIndexSearchResultTypeKey(resultTypeKey);

        // Create an index search keys list and add the previously defined key to it
        final List<IndexSearchKey> indexSearchKeys = Collections.singletonList(indexSearchKey);

        // Create an index search filter with the keys previously defined
        final IndexSearchFilter indexSearchFilter = new IndexSearchFilter(NO_EXCLUSION_SEARCH_FILTER,
                indexSearchKeys);

        // Set exclude flag to true
        indexSearchFilter.setIsExclusionSearchFilter(true);

        List<IndexSearchFilter> indexSearchFilters = Collections.singletonList(indexSearchFilter);

        //result type facet only
        testIndexSearch(fields, indexSearchFilters, null, ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchWithHighlightingEnabled() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        testIndexSearch(fields, null, null, ENABLE_HIT_HIGHLIGHTING);
    }

    @Test
    public void indexSearchWithColumnMatchAndHighlightingEnabled() throws IOException {
        // Create a new fields set that will be used when testing the index search method
        final Set<String> fields = new HashSet<>();

        // Create a set of match fields.
        final Set<String> match = Sets.newHashSet(MATCH_COLUMN);

        testIndexSearch(SEARCH_TERM, fields, match, null, null, ENABLE_HIT_HIGHLIGHTING, false, false,
                DISABLE_COLUMN_FIELDS);
    }

    private void testIndexSearch(Set<String> fields, List<IndexSearchFilter> searchFilters, List<String> facetList,
            boolean isHitHighlightingEnabled) throws IOException {
        testIndexSearch(SEARCH_TERM, fields, NO_MATCH, searchFilters, facetList, isHitHighlightingEnabled, false,
                false, DISABLE_COLUMN_FIELDS);
    }

    private void testIndexSearch(String searchTerm, Set<String> fields, List<IndexSearchFilter> searchFilters,
            List<String> facetList, boolean isHitHighlightingEnabled) throws IOException {
        testIndexSearch(searchTerm, fields, NO_MATCH, searchFilters, facetList, isHitHighlightingEnabled, false,
                false, DISABLE_COLUMN_FIELDS);
    }

    private void testIndexSearch(String searchTerm, Set<String> fields, Set<String> match,
            List<IndexSearchFilter> searchFilters, List<String> facetList, boolean isHitHighlightingEnabled,
            boolean testExceptions, boolean setInvalidSearchResultIndexName, boolean isColumnFields)
            throws IOException {
        // Build the mocks
        SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class);
        SearchRequestBuilder searchRequestBuilderWithSource = mock(SearchRequestBuilder.class);
        SearchRequestBuilder searchRequestBuilderWithSize = mock(SearchRequestBuilder.class);
        SearchRequestBuilder searchRequestBuilderWithSorting = mock(SearchRequestBuilder.class);
        SearchRequestBuilder searchRequestBuilderWithHighlighting = mock(SearchRequestBuilder.class);

        SearchResponse searchResponse = mock(SearchResponse.class);
        SearchHits searchHits = mock(SearchHits.class);
        SearchHit searchHit1 = mock(SearchHit.class);
        SearchHit searchHit2 = mock(SearchHit.class);
        SearchShardTarget searchShardTarget1 = mock(SearchShardTarget.class);
        SearchShardTarget searchShardTarget2 = mock(SearchShardTarget.class);
        SearchHit[] searchHitArray = new SearchHit[2];
        searchHitArray[0] = searchHit1;
        searchHitArray[1] = searchHit2;

        BoolQueryBuilder boolQueryBuilder = mock(BoolQueryBuilder.class);

        HighlightField highlightField = mock(HighlightField.class);
        when(highlightField.getName()).thenReturn("displayName");

        Text[] value = { new Text("match <hlt>fragment</hlt class=\"highlight\">"),
                new Text("<hlt class=\"highlight\">match</hlt>") };
        when(highlightField.getFragments()).thenReturn(value);

        @SuppressWarnings("unchecked")
        ListenableActionFuture<SearchResponse> listenableActionFuture = mock(ListenableActionFuture.class);

        final String highlightFieldsConfigValue = "{\"highlightFields\":[{\"fieldName\":\"displayName\",\"fragmentSize\":100,\"matchedFields\":[\"displayName\",\"displayName.stemmed\",\"displayName.ngrams\"],\"numOfFragments\":5}]}";

        final String highlightFieldsColumnMatchConfigValue = "{\"highlightFields\":[{\"fieldName\":\"columnName\",\"fragmentSize\":100,\"matchedFields\":[\"columnName\",\"columnName.stemmed\",\"columnName.ngrams\"],\"numOfFragments\":5}]}";

        // Mock the call to external methods
        when(configurationHelper.getProperty(ConfigurationValue.TAG_SHORT_DESCRIPTION_LENGTH, Integer.class))
                .thenReturn(300);
        when(configurationHelper.getProperty(ConfigurationValue.BUSINESS_OBJECT_DEFINITION_SHORT_DESCRIPTION_LENGTH,
                Integer.class)).thenReturn(300);
        when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_NGRAMS))
                .thenReturn("{\"displayName\":\"1.0\"}");
        when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_STEMMED))
                .thenReturn("{\"displayName\":\"1.0\"}");
        when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_SHINGLES))
                .thenReturn("{\"displayName\":\"1.0\"}");
        when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_HIGHLIGHT_PRETAGS))
                .thenReturn("<hlt class=\"highlight\">");
        when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_HIGHLIGHT_POSTTAGS))
                .thenReturn("</hlt>");
        if (match != null && match.contains(MATCH_COLUMN)) {
            when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_COLUMN_MATCH_HIGHLIGHT_FIELDS))
                    .thenReturn(highlightFieldsColumnMatchConfigValue);
        } else {
            when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_HIGHLIGHT_FIELDS))
                    .thenReturn(highlightFieldsConfigValue);
        }
        when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_BEST_FIELDS_QUERY_BOOST, Float.class))
                .thenReturn(1f);
        when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_PHRASE_PREFIX_QUERY_BOOST,
                Float.class)).thenReturn(1f);
        when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_PHRASE_QUERY_BOOST, Float.class))
                .thenReturn(1f);
        when(configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_PHRASE_QUERY_SLOP, Integer.class))
                .thenReturn(5);

        Map<String, String> fieldsBoostMap = new HashMap<>();
        fieldsBoostMap.put("displayName", "1.0");

        if (isColumnFields) {
            fieldsBoostMap.put(COLUMNS_NAME_FIELD, "1.0");
            fieldsBoostMap.put(SCHEMA_COLUMNS_NAME_FIELD, "1.0");
        }

        if (testExceptions) {
            when(jsonHelper.unmarshallJsonToObject(Map.class, "{\"displayName\":\"1.0\"}"))
                    .thenThrow(new IOException());
        } else {
            when(jsonHelper.unmarshallJsonToObject(Map.class, "{\"displayName\":\"1.0\"}"))
                    .thenReturn(fieldsBoostMap);
        }

        IndexSearchHighlightField indexSearchHighlightField = new IndexSearchHighlightField("displayName", 100,
                Arrays.asList("displayName", "displayName.stemmed", "displayName.ngrams"), 5);

        IndexSearchHighlightFields highlightFields = new IndexSearchHighlightFields(
                Collections.singletonList(indexSearchHighlightField));

        IndexSearchHighlightField indexSearchHighlightFieldColumnOnly = new IndexSearchHighlightField("columnName",
                100, Arrays.asList("columnName", "columnName.stemmed", "columnName.ngrams"), 5);

        IndexSearchHighlightFields highlightFieldsColumnOnly = new IndexSearchHighlightFields(
                Collections.singletonList(indexSearchHighlightFieldColumnOnly));

        if (testExceptions) {
            when(jsonHelper.unmarshallJsonToObject(IndexSearchHighlightFields.class, highlightFieldsConfigValue))
                    .thenThrow(new IOException());
        } else {
            if (match != null && match.contains(MATCH_COLUMN)) {
                when(jsonHelper.unmarshallJsonToObject(IndexSearchHighlightFields.class,
                        highlightFieldsColumnMatchConfigValue)).thenReturn(highlightFieldsColumnOnly);
            } else {
                when(jsonHelper.unmarshallJsonToObject(IndexSearchHighlightFields.class,
                        highlightFieldsConfigValue)).thenReturn(highlightFields);
            }
        }

        when(searchRequestBuilder.setSource(any(SearchSourceBuilder.class)))
                .thenReturn(searchRequestBuilderWithSource);
        when(searchRequestBuilderWithSource.setSize(SEARCH_RESULT_SIZE)).thenReturn(searchRequestBuilderWithSize);
        when(searchRequestBuilderWithSize.addSort(any(SortBuilder.class)))
                .thenReturn(searchRequestBuilderWithSorting);
        when(searchRequestBuilderWithSorting.highlighter(any(HighlightBuilder.class)))
                .thenReturn(searchRequestBuilderWithHighlighting);

        when(searchRequestBuilder.execute()).thenReturn(listenableActionFuture);
        when(listenableActionFuture.actionGet()).thenReturn(searchResponse);
        when(searchResponse.getHits()).thenReturn(searchHits);
        when(searchHits.hits()).thenReturn(searchHitArray);
        Map<String, Object> sourceMap1 = new HashMap<>();
        Map<String, Object> tagTypeMap = new HashMap<>();
        tagTypeMap.put(CODE, TAG_TYPE_CODE);
        sourceMap1.put(TAG_TYPE, tagTypeMap);
        when(searchHit1.sourceAsMap()).thenReturn(sourceMap1);
        Map<String, Object> sourceMap2 = new HashMap<>();
        Map<String, Object> businessObjectDefinitionMap = new HashMap<>();
        businessObjectDefinitionMap.put(CODE, NAMESPACE_CODE);
        sourceMap2.put(NAMESPACE, businessObjectDefinitionMap);
        when(searchHit2.sourceAsMap()).thenReturn(sourceMap2);
        when(searchHit1.getShard()).thenReturn(searchShardTarget1);
        when(searchHit2.getShard()).thenReturn(searchShardTarget2);
        when(searchShardTarget1.getIndex()).thenReturn(TAG_SEARCH_INDEX_NAME);
        when(searchShardTarget2.getIndex()).thenReturn(BUSINESS_OBJECT_DEFINITION_SEARCH_INDEX_NAME);
        when(searchHits.getTotalHits()).thenReturn(200L);

        Map<String, HighlightField> highlightFieldMap = new HashMap<>();
        highlightFieldMap.put("displayName", highlightField);

        when(searchHit1.getHighlightFields()).thenReturn(highlightFieldMap);
        when(searchHit2.getHighlightFields()).thenReturn(highlightFieldMap);

        // Create index search request
        final IndexSearchRequest indexSearchRequest = new IndexSearchRequest(searchTerm, searchFilters, facetList,
                isHitHighlightingEnabled);

        List<TagTypeIndexSearchResponseDto> tagTypeIndexSearchResponseDtos = Collections
                .singletonList(new TagTypeIndexSearchResponseDto("code",
                        Collections.singletonList(new TagIndexSearchResponseDto("tag1", 1, null)), null));
        List<ResultTypeIndexSearchResponseDto> resultTypeIndexSearchResponseDto = Collections
                .singletonList(new ResultTypeIndexSearchResponseDto("type", 1, null));

        when(elasticsearchHelper.getNestedTagTagIndexSearchResponseDto(searchResponse))
                .thenReturn(tagTypeIndexSearchResponseDtos);
        when(elasticsearchHelper.getResultTypeIndexSearchResponseDto(searchResponse))
                .thenReturn(resultTypeIndexSearchResponseDto);
        when(elasticsearchHelper.getFacetsResponse(any(ElasticsearchResponseDto.class),
                eq(BUSINESS_OBJECT_DEFINITION_SEARCH_INDEX_NAME), eq(TAG_SEARCH_INDEX_NAME))).thenCallRealMethod();
        when(elasticsearchHelper.addIndexSearchFilterBooleanClause(any(), any(), any()))
                .thenReturn(boolQueryBuilder);
        when(elasticsearchHelper.addFacetFieldAggregations(any(), any(SearchRequestBuilder.class)))
                .thenReturn(searchRequestBuilder);

        when(herdSearchQueryHelper.determineNegationTermsPresent(any(IndexSearchRequest.class)))
                .thenCallRealMethod();
        when(herdSearchQueryHelper.extractNegationTerms(any(IndexSearchRequest.class))).thenCallRealMethod();
        when(herdSearchQueryHelper.extractSearchPhrase(any(IndexSearchRequest.class))).thenCallRealMethod();

        SearchResult searchResult = mock(SearchResult.class);
        when(jestClientHelper.execute(any())).thenReturn(searchResult);

        List<SearchResult.Hit<Map, Void>> searchHitList = new ArrayList<>();
        Gson gson = new Gson();
        Map<String, Object> map = new HashMap<>();
        map.put(DISPLAY_NAME_SOURCE, "Display Name");
        Map<String, Object> codeMap = new HashMap<>();
        codeMap.put(CODE, "Code");
        map.put(TAG_TYPE, codeMap);
        map.put(NAMESPACE, codeMap);
        JsonElement element = gson.toJsonTree(map);
        List<String> highlightList = new ArrayList<>();
        highlightList.add("Highlight 1");
        Map<String, List<String>> highlightMap = new HashMap<>();
        highlightMap.put("field", highlightList);

        SearchResult.Hit<Map, Void> hit1 = new SearchResult(gson).new Hit(HashMap.class, element, HashMap.class,
                null, highlightMap, null, setInvalidSearchResultIndexName ? INVALID_VALUE : TAG_SEARCH_INDEX_NAME,
                TAG_SEARCH_INDEX_NAME, "type", 1.0);
        SearchResult.Hit<Map, Void> hit2 = new SearchResult(gson).new Hit(HashMap.class, element, HashMap.class,
                null, highlightMap, null, BUSINESS_OBJECT_DEFINITION_SEARCH_INDEX_NAME,
                BUSINESS_OBJECT_DEFINITION_SEARCH_INDEX_NAME, "type", 2.0);
        searchHitList.add(hit1);
        searchHitList.add(hit2);

        when(searchResult.getHits(Map.class)).thenReturn(searchHitList);
        when(searchResult.getTotal()).thenReturn(200L);

        MetricAggregation metricAggregation = mock(MetricAggregation.class);
        TermsAggregation termsAggregation = mock(TermsAggregation.class);
        when(searchResult.getAggregations()).thenReturn(metricAggregation);
        when(metricAggregation.getTermsAggregation(TAG_TYPE_FACET_AGGS)).thenReturn(termsAggregation);
        List<TermsAggregation.Entry> buckets = new ArrayList<>();
        TermsAggregation.Entry entry1 = mock(TermsAggregation.Entry.class);
        TermsAggregation.Entry entry2 = mock(TermsAggregation.Entry.class);
        buckets.add(entry1);
        buckets.add(entry2);
        when(termsAggregation.getBuckets()).thenReturn(buckets);

        // Call the method under test
        IndexSearchResponse indexSearchResponse = indexSearchDao.indexSearch(indexSearchRequest, fields, match,
                BUSINESS_OBJECT_DEFINITION_SEARCH_INDEX_NAME, TAG_SEARCH_INDEX_NAME);
        List<IndexSearchResult> indexSearchResults = indexSearchResponse.getIndexSearchResults();

        assertThat("Index search results list is null.", indexSearchResults, not(nullValue()));
        assertThat(indexSearchResponse.getTotalIndexSearchResults(), is(200L));

        // Verify external method calls.
        if (StringUtils.isNotEmpty(searchTerm)) {
            verify(herdSearchQueryHelper).determineNegationTermsPresent(indexSearchRequest);
            verify(herdSearchQueryHelper).extractNegationTerms(indexSearchRequest);
            verify(herdSearchQueryHelper).extractSearchPhrase(indexSearchRequest);
            verify(configurationHelper, times(3))
                    .getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_STEMMED);
            verify(configurationHelper).getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_NGRAMS);
            verify(configurationHelper).getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_SHINGLES);
            verify(configurationHelper).getProperty(ConfigurationValue.ELASTICSEARCH_PHRASE_PREFIX_QUERY_BOOST,
                    Float.class);
            verify(configurationHelper).getProperty(ConfigurationValue.ELASTICSEARCH_BEST_FIELDS_QUERY_BOOST,
                    Float.class);
            verify(configurationHelper, times(2)).getProperty(ConfigurationValue.ELASTICSEARCH_PHRASE_QUERY_BOOST,
                    Float.class);
            verify(configurationHelper, times(5)).getProperty(ConfigurationValue.ELASTICSEARCH_PHRASE_QUERY_SLOP,
                    Integer.class);
            verify(jsonHelper, times(5)).unmarshallJsonToObject(Map.class, "{\"displayName\":\"1.0\"}");
        }

        verify(configurationHelper).getProperty(ConfigurationValue.TAG_SHORT_DESCRIPTION_LENGTH, Integer.class);
        verify(configurationHelper)
                .getProperty(ConfigurationValue.BUSINESS_OBJECT_DEFINITION_SHORT_DESCRIPTION_LENGTH, Integer.class);

        if (CollectionUtils.isNotEmpty(indexSearchRequest.getIndexSearchFilters())) {
            verify(elasticsearchHelper).addIndexSearchFilterBooleanClause(
                    indexSearchRequest.getIndexSearchFilters(), BUSINESS_OBJECT_DEFINITION_SEARCH_INDEX_NAME,
                    TAG_SEARCH_INDEX_NAME);
        }

        if (indexSearchRequest.isEnableHitHighlighting() != null) {
            verifyHitHighlightingInteractions(searchRequestBuilder, indexSearchRequest.isEnableHitHighlighting(),
                    match);
        }

        if (CollectionUtils.isNotEmpty(indexSearchRequest.getFacetFields())) {
            verify(elasticsearchHelper).addFacetFieldAggregations(any(), any(SearchRequestBuilder.class));

            if (indexSearchRequest.getFacetFields().contains(ElasticsearchHelper.TAG_FACET)) {
                verify(elasticsearchHelper).getNestedTagTagIndexSearchResponseDto(searchResult);
                verify(elasticsearchHelper).getTagTagIndexSearchResponseDto(searchResult);
            }

            if (indexSearchRequest.getFacetFields().contains(ElasticsearchHelper.RESULT_TYPE_FACET)) {
                verify(elasticsearchHelper).getResultTypeIndexSearchResponseDto(searchResult);
            }

            verify(elasticsearchHelper).getFacetsResponse(any(ElasticsearchResponseDto.class),
                    eq(BUSINESS_OBJECT_DEFINITION_SEARCH_INDEX_NAME), eq(TAG_SEARCH_INDEX_NAME));
        }

        verify(jestClientHelper).execute(any());
        verify(searchResult).getTotal();
        verify(searchResult).getHits(Map.class);
        verifyNoMoreInteractions(searchRequestBuilder, searchRequestBuilderWithSource, searchRequestBuilderWithSize,
                searchRequestBuilderWithSorting, searchRequestBuilderWithHighlighting, searchResponse, searchHits,
                searchHit1, searchHit2, searchShardTarget1, searchShardTarget2, highlightField,
                listenableActionFuture, searchResult, metricAggregation, termsAggregation, entry1, entry2);
        verifyNoMoreInteractionsHelper();
    }

    private void verifyHitHighlightingInteractions(SearchRequestBuilder searchRequestBuilder,
            boolean isHitHighlightingEnabled, Set<String> match) throws IOException {
        if (isHitHighlightingEnabled) {
            // verify interactions with the helpers which is required to fetch highlighting config
            verify(jsonHelper, times(5)).unmarshallJsonToObject(eq(Map.class), any(String.class));
            verify(jsonHelper).unmarshallJsonToObject(eq(IndexSearchHighlightFields.class), any(String.class));
            verify(configurationHelper, times(3)).getProperty(ConfigurationValue.ELASTICSEARCH_HIGHLIGHT_POSTTAGS);
            verify(configurationHelper, times(3)).getProperty(ConfigurationValue.ELASTICSEARCH_HIGHLIGHT_PRETAGS);
            if (match != null && match.contains(MATCH_COLUMN)) {
                verify(configurationHelper)
                        .getProperty(ConfigurationValue.ELASTICSEARCH_COLUMN_MATCH_HIGHLIGHT_FIELDS);
            } else {
                verify(configurationHelper).getProperty(ConfigurationValue.ELASTICSEARCH_HIGHLIGHT_FIELDS);
            }
        } else {
            // verify highlighting is not added to the query if not highlighting is disabled
            verify(searchRequestBuilder, times(0)).highlighter(any(HighlightBuilder.class));

            // verify highlighting-specific configuration values are not fetched if highlighting is disabled
            verify(configurationHelper, times(0)).getProperty(ConfigurationValue.ELASTICSEARCH_HIGHLIGHT_POSTTAGS);
            verify(configurationHelper, times(0)).getProperty(ConfigurationValue.ELASTICSEARCH_HIGHLIGHT_PRETAGS);
            verify(configurationHelper, times(0)).getProperty(ConfigurationValue.ELASTICSEARCH_HIGHLIGHT_FIELDS);
        }
    }

    /**
     * Checks if any of the mocks has any interaction.
     */
    private void verifyNoMoreInteractionsHelper() {
        verifyNoMoreInteractions(configurationHelper, jsonHelper, elasticsearchHelper, jestClientHelper,
                herdSearchQueryHelper);
    }
}