Как написать правильный модульный тест для Elasticsearch в Java - PullRequest
0 голосов
/ 05 ноября 2018

Обзор:

Я совершенно новичок в поисковом тестировании Elastic и собираюсь добавить правильные юнит-тесты. Совместимость проекта:

  • Java 8
  • Elasticsearch 6.2.4
  • Проект использует низкоуровневый клиент отдыха для извлечения данных из ES

Более подробная информация о конфигурации ES приведена ниже:

import static java.net.InetAddress.getByName;
import static java.util.Arrays.stream;

import java.net.UnknownHostException;
import java.util.Map;
import java.util.Objects;

import javax.inject.Inject;

import org.apache.http.HttpHost;

import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import au.com.api.util.RestClientUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
public class ElasticConfiguration implements InitializingBean{

    @Value(value = "${elasticsearch.hosts}")
    private String[] hosts;

    @Value(value = "${elasticsearch.httpPort}")
    private int httpPort;

    @Value(value = "${elasticsearch.tcpPort}")
    private int tcpPort;

    @Value(value = "${elasticsearch.clusterName}")
    private String clusterName;

    @Inject
    private RestClientUtil client;

    @Bean
    public RestHighLevelClient restHighClient() {

        return new RestHighLevelClient(RestClient.builder(httpHosts()));
    }

    @Bean
    @Deprecated
    public RestClient restClient() {

        return RestClient.builder(httpHosts()).build();

    }

    /**
     * @return TransportClient
     * @throws UnknownHostException
     */
    @SuppressWarnings("resource")
    @Bean
    public TransportClient transportClient() throws UnknownHostException{

        Settings settings = Settings.builder()
                .put("cluster.name", clusterName).build();

        return new PreBuiltTransportClient(settings).addTransportAddresses(transportAddresses());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.debug("loading search templates...");
        try {
            for (Map.Entry<String, String> entry : Constants.SEARCH_TEMPLATE_MAP.entrySet()) {
                client.putInlineSearchTemplateToElasticsearch(entry.getKey(), entry.getValue());
            }
        } catch (Exception e) {
            log.error("Exception has occurred in putting search templates into ES.", e);
        }
    }

    private HttpHost[] httpHosts() {
        return stream(hosts).map(h -> new HttpHost(h, httpPort, "http")).toArray(HttpHost[]::new);
    }

    private TransportAddress[] transportAddresses() throws UnknownHostException {
        TransportAddress[] transportAddresses = stream(hosts).map(h -> {
            try {
                return new TransportAddress(getByName(h), tcpPort);
            } catch (UnknownHostException e) {
                log.error("Exception has occurred in creating ES TransportAddress. host: '{}', tcpPort: '{}'", h, tcpPort, e);
            }
            return null;
        }).filter(Objects::nonNull).toArray(TransportAddress[]::new);

        if (transportAddresses.length == 0) {
            throw new UnknownHostException();
        }
        return transportAddresses;
    }
}

Проблема:

Я не знаю, как Mock ES или как тестировать ES без запуска автономной ES на моей машине. Пожалуйста, используйте следующий класс в качестве примера и дайте мне знать, как я могу написать контрольный пример (модульный тест без интеграции) для метода getSearchResponse:

    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;

    import org.elasticsearch.action.search.SearchRequest;
    import org.elasticsearch.action.search.SearchResponse;
    import org.elasticsearch.client.transport.NoNodeAvailableException;
    import org.elasticsearch.client.transport.TransportClient;
    import org.elasticsearch.script.ScriptType;
    import org.elasticsearch.script.mustache.SearchTemplateRequestBuilder;
    import org.elasticsearch.search.Scroll;
    import org.elasticsearch.search.aggregations.Aggregation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.MessageSource;
    import org.springframework.stereotype.Repository;
    @Slf4j
@Repository
@NoArgsConstructor
public abstract class NewBaseElasticsearchRepository {

    @Autowired
    protected NewIndexLocator newIndexLocator;

    @Value(value = "${elasticsearch.client.timeout}")
    private Long timeout;

    @Autowired
    protected TransportClient transportClient;

    @Autowired
    protected ThresholdService thresholdService;

    @Autowired
    protected MessageSource messageSource;

    /**
     * @param script         the name of the script to be executed
     * @param templateParams a map of the parameters to be sent to the script
     * @param indexName      the index to target (an empty indexName will search all indexes)
     *
     * @return a Search Response object containing details of the request results from Elasticsearch
     *
     * @throws NoNodeAvailableException thrown when the transport client cannot connect to any ES Nodes (or Coordinators)
     * @throws Exception                thrown for all other request errors such as parsing and non-connectivity related issues
     */
    protected SearchResponse getSearchResponse(String script, Map<String, Object> templateParams, String... indexName) {
        log.debug("transport client >> index name --> {}", Arrays.toString(indexName));

        SearchResponse searchResponse;

        try {
            searchResponse = new SearchTemplateRequestBuilder(transportClient)
                .setScript(script)
                .setScriptType(ScriptType.STORED)
                .setScriptParams(templateParams)
                .setRequest(new SearchRequest(indexName))
                .execute()
                .actionGet(timeout)
                .getResponse();
        } catch (NoNodeAvailableException e) {
            log.error(ELASTIC_SEARCH_EXCEPTION_NOT_FOUND, e.getMessage());
            throw new ElasticSearchException(ELASTIC_SEARCH_EXCEPTION_NOT_FOUND);
        } catch (Exception e) {
            log.error(ELASTIC_SEARCH_EXCEPTION, e.getMessage());
            throw new ElasticSearchException(ELASTIC_SEARCH_EXCEPTION);
        }

        log.debug("searchResponse ==> {}", searchResponse);
        return searchResponse;
    }

Итак, я был бы признателен, если бы вы взглянули на пример класса и поделились со мной вашими подлинными решениями о том, как я могу высмеивать TransportClient и получить правильный ответ от SearchResponse объекта.


Примечание:

  • Я пытался использовать ESTestCase из org.elasticsearch.test:framework:6.2.4, но столкнулся с проблемой jar hell и не смог ее решить. В то же время я не смог найти никаких документов, связанных с этим или модульным тестированием Java ES в целом.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...