Kiểm tra tích hợp Amazon ElasticSearch Java

Amazon cung cấp dịch vụ ElasticSearch Cloud. Như bạn có thể biết, Amazon dựa trên một nhánh rẽ có tên là Opendistro sau một số vấn đề với sản phẩm gốc. Sản phẩm Amazon này có vòng đời riêng với các thẻ lập phiên bản khác với sản phẩm ElasticSearch ban đầu. Vì vậy, khi kiểm tra mã máy khách Java của bạn với máy chủ để kiểm tra tích hợp, thật không dễ dàng để đưa ra một môi trường hợp lệ mô phỏng chặt chẽ những gì đang xảy ra với sản phẩm Amazon thực tế.

Vì vậy, bài viết này cung cấp một ví dụ làm việc về cách thực hiện kiểm tra tích hợp cho các ứng dụng khách Java của bạn như một phần của quá trình xây dựng dự án của bạn và phát hiện các vấn đề tích hợp trước khi chuyển sang môi trường Amazon. Điều này sẽ cho phép nhóm phát triển của bạn xác định sớm các vấn đề trong quy trình của bạn và có khả năng tái tạo các vấn đề sản xuất trong dev env để khắc phục nhanh chóng.

Sự phụ thuộc

Hãy bắt đầu với danh sách phụ thuộc:

<dependency>
   <groupId>org.junit.jupiter</groupId>
   <artifactId>junit-jupiter-engine</artifactId>
   <version>5.4.0</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.testcontainers</groupId>
   <artifactId>testcontainers</artifactId>
   <version>1.15.1</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.elasticsearch.client</groupId>
   <artifactId>elasticsearch-rest-high-level-client</artifactId>
   <version>7.10.2</version>
</dependency>

Sau đó, chúng tôi cần Testcontainers, đây là công cụ kiểm tra cơ bản cần thiết để hoạt động với hình ảnh Docker và có thể khởi động máy chủ Amazon ElasticSearch để thử nghiệm. Đối với liên kết kiểm tra Yêu cầu Testcontainers mới hơn .

Phần phụ thuộc Java ElastiSearch Client sẽ được sử dụng để gửi các truy vấn đến máy chủ.

Công cụ Awaitility được sử dụng để xác định điều kiện hẹn giờ để máy chủ sẵn sàng nhận yêu cầu

Thử nghiệm Skeleton

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.nio.entity.NStringEntity;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.ClassRule;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import static org.junit.Assert.assertTrue;
public class OpendistroCompTest {

    public static final DockerImageName OPENDISTRO_IMAGE = DockerImageName.parse("amazon/opendistro-for-elasticsearch:1.11.0");

    private static final String ELASTICSEARCH_USERNAME = "admin";
    private static final String ELASTICSEARCH_PASSWORD = "admin";

    @ClassRule
    public static GenericContainer<?> container;

    private static RestHighLevelClient esClient;
    private static RestClient restClient;

    @Test
    public void checkServerHealth() throws Exception {

        Response response = restClient.performRequest(new Request("GET", "/_cluster/health"));
    }

    private static class DefaultTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }

    @BeforeAll
    public static void prepareESContainer() throws Exception {
        // Create the elasticsearch container.
        // configure the SSLContext with a TrustManager
        //this is because local ES certificate is not bound to the proper ip
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
        SSLContext.setDefault(ctx);

        // Start the container. This step might take some time...
        container =
        new GenericContainer<>(OPENDISTRO_IMAGE)
                .withExposedPorts(9200, 9600).withEnv("discovery.type", "single-node").waitingFor(Wait.forLogMessage(".*Hot-reloading of audit configuration is enabled.*\\n", 1));
        container.start();
        String hostAddr = container.getContainerInfo().getNetworkSettings().getIpAddress();
        HttpHost httpHost1 = new HttpHost(hostAddr, 9200, "https");


        // Create the secured client.
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD));

        RestClientBuilder builder = RestClient.builder(httpHost1).setHttpClientConfigCallback(
                httpClientBuilder -> {
                    httpClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
                    return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                });
        esClient = new RestHighLevelClient(builder);
        restClient = RestClient.builder(httpHost1).setHttpClientConfigCallback(
                httpClientBuilder -> {
                    httpClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
                    return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                }).build();

    }


    

   @AfterAll
    public static void cleanUp() throws Exception {
       // stop the client
        esClient.close();
        restClient.close();

        // Stop the container.
        container.stop();
        container.close();
    }
}

cuộn tròn -XGET https://172.17.0.3:9200-u admin: admin - không an toàn
{
“name”: “4c3f689ddd76”,
“cluster_name”: “docker-cluster”,
“cluster_uuid”: “n96mfPN3QYOx3kPb2NdcWg”,
“version”: {
“number”: “7.9.1”,
“ build_flavor ”:“ oss ”,
“ build_type ”:“ tar ”,
“ build_hash ”:“ 083627f112ba94dffc1232e8b42b73492789ef91 ”,
“ build_date ”:“ 2020–09–01T21: 22: 21.964974Z ”,
“ build_snapshot ”: false,
“ build_version ”: false, “ “8.6.2”,
“minimal_wire_compatibility_version”: “6.8.0”,
“minimal_index_compatibility_version”: “6.0.0-beta1”
},
“khẩu hiệu”: “Bạn biết đấy, dành cho Tìm kiếm”
}

Các thuộc tính đáng nói là:

  • Số: Đây là phiên bản sản phẩm của Amazon. Nó phải tương quan với một cái bạn đặt trong Amazon Console cho miền ElasticSearch của bạn.
  • Lucene_version: Đây là phiên bản của công cụ tìm kiếm Lucene nội bộ được máy chủ sử dụng.
  • Dây tối thiểu Phiên bản tương thích: Phiên bản tối thiểu để các nút khác trong cụm phối hợp đúng.
  • Khả năng tương thích chỉ mục tối thiểu: Tương tự như trước nhưng liên quan đến việc đọc tệp từ một nút cũ hơn.

container =
                new GenericContainer<>(OPENDISTRO_IMAGE)
                        .withExposedPorts(9200, 9600).withEnv("discovery.type", "single-node").waitingFor(Wait.forLogMessage(".*Hot-reloading of audit configuration is enabled.*\\n", 1));;
        container.start();

Sau đó, chúng tôi tiếp tục bằng cách tạo các máy khách Java. Bạn sẽ nhận thấy có một số tinh chỉnh bảo mật để cho phép truy cập vào máy chủ cục bộ. Nếu điều đó là quan trọng đối với thử nghiệm của bạn, bạn sẽ cần tìm ra cách truy cập phiên bản cục bộ bằng cách sử dụng localhost thích hợp được xác định trong chứng chỉ máy chủ, để chúng khớp đúng cách:

RestClientBuilder builder = RestClient.builder....

public void checkServerHealth() throws Exception {

        Response response = restClient.performRequest(new Request("GET", "/_cluster/health"));
    }

@AfterAll
    public static void cleanUp() throws Exception {
       // stop the client
        esClient.close();
        restClient.close();

        // Stop the container.
        container.stop();
        container.close();
    }

Quản lý chỉ mục và dân số dữ liệu

Testsuite của bạn có thể liên quan đến quản lý chỉ mục hoặc chỉ các truy vấn, hoặc có thể cả hai. Trong trường hợp của chúng tôi, chúng tôi muốn kiểm tra các truy vấn mã Java Lambda của mình, nhưng điều này yêu cầu phải có các chỉ mục và dữ liệu thực tế trong máy chủ để thực hiện các truy vấn. Tôi đang chia sẻ một số công cụ chúng tôi sử dụng để tạo chỉ mục, mẫu và tải một số dữ liệu.

private static String loadResource(String name) throws IOException {
    final InputStream data = CdrCompTest.class.getResourceAsStream(name);
    String template = IOUtils.toString(data, StandardCharsets.UTF_8);
    return template;
}

private static void createIndex(String name) throws IOException {
    CreateIndexRequest request = new CreateIndexRequest(name);
    esClient.indices().create(request, RequestOptions.DEFAULT);
}

private static void addDoc(String index, String dataFile) throws Exception {
    String jsonString = loadResource(dataFile);
    String[] ss = jsonString.split(";");

    BulkRequest request = new BulkRequest();
    for (String s : ss) {
        IndexRequest iRequest = new IndexRequest(index, "_doc");
        iRequest.source(s, XContentType.JSON);
        request.add(iRequest);
    }

    BulkResponse bulkResponse = esClient.bulk(request, RequestOptions.DEFAULT);
}

private static void prepareIndexes(GenericContainer container) throws Exception {
    // creating of index templates
    for (String s : templateNames) {
        String template = loadResource("/" + s + ".txt");

        Request request = new Request("PUT", "/_template/" + s);
        NStringEntity entity = new NStringEntity(template, ContentType.APPLICATION_JSON);
        request.setEntity(entity);
        Response response = restClient.performRequest(request);

        GetIndexTemplatesRequest p = new GetIndexTemplatesRequest(s);
        GetIndexTemplatesResponse resp = esClient.indices().getIndexTemplate(p, RequestOptions.DEFAULT);
        int i1 = 0;
    }

    // creating of indeces
    for (String name : indexNames) {
        createIndex(name);
    }
}

private static void deleteIndex(String name) throws IOException {
    DeleteIndexRequest request = new DeleteIndexRequest(name);
    esClient.indices().delete(request, RequestOptions.DEFAULT);
}

prepareIndexes(container);

for (String s : dataNames) {
    addDoc(s, "/" + s + ".txt");
}

Phần kết luận

Môi trường thử nghiệm nhỏ này sẽ cho phép bạn kiểm tra mọi tương tác với máy chủ và kiểm tra xem mã máy khách của bạn có hoạt động đúng hay không. Chúng tôi hy vọng bài viết này cho phép các nhóm khác cải thiện quy trình của họ bằng cách thêm kiểm tra tích hợp vào ứng dụng Java Amazon ElasticSearch của họ.

Giải pháp này là một nỗ lực tổng hợp từ nhóm Core Network ở Telestax, và do đó thành tích đến từ nhóm, kudo cho nhóm !!

Suggested posts

Định cấu hình và sử dụng Apache Kafka với Spring Boot

Kafka với chiếc ủng lò xo

Định cấu hình và sử dụng Apache Kafka với Spring Boot

Giới thiệu Apache Kafka là một nền tảng phát trực tuyến phân tán mã nguồn mở, xử lý luồng dữ liệu thời gian thực quy mô lớn, thông lượng cao, có khả năng chịu lỗi. Hệ thống này dựa trên mô hình đăng ký xuất bản trong đó nhà sản xuất xuất bản tin nhắn cho các chủ đề và người tiêu dùng đăng ký các chủ đề đó để sử dụng tin nhắn.

Mastering Mobile Development: Cách chọn ngôn ngữ lập trình tốt nhất cho ứng dụng của bạn

Mastering Mobile Development: Cách chọn ngôn ngữ lập trình tốt nhất cho ứng dụng của bạn

Phát triển di động đã trở thành một thành phần quan trọng để các doanh nghiệp thành công trong thế giới kỹ thuật số ngày nay. Là nhà phát triển ứng dụng dành cho thiết bị di động, điều cần thiết là chọn ngôn ngữ lập trình phù hợp để xây dựng ứng dụng của bạn.

Related posts

"Hé lộ rãnh Mariana: Hé lộ những sự thật kinh hoàng ẩn giấu của vực thẳm"

"Hé lộ rãnh Mariana: Hé lộ những sự thật kinh hoàng ẩn giấu của vực thẳm"

Giới thiệu: Chào mừng những độc giả dũng cảm đến với cuộc hành trình sẽ đưa chúng ta đến những nơi sâu thẳm nhất của hành tinh chúng ta. Trong blog này, chúng tôi đi sâu vào thế giới bí ẩn của Rãnh Mariana, khám phá những bí mật ẩn giấu của nó và khám phá những sự thật lạnh thấu xương nằm bên dưới bề mặt của nó.

Nghệ thuật có bao giờ phi chính trị?

Nghệ thuật có bao giờ phi chính trị?

Hôm qua, chúng ta đã khép lại cuộc thi Ca khúc Eurovision năm nay bằng một đêm chung kết hoành tráng, hỗn loạn, nơi ca sĩ người Thụy Điển Loreen đã mang về chiếc cúp, trở thành người phụ nữ đầu tiên giành chiến thắng hai lần và mang vương miện về cho Thụy Điển 50 năm sau khi ABBA giành chiến thắng trong cuộc thi với “Waterloo”. Họ tiếp tục trở thành một trong những nghệ sĩ lớn nhất trong thể loại nhạc pop.

Tìm kiếm thông tin về tên miền

Đoạn trích từ Small, Sharp Software Tools của Brian P. Hogan

Tìm kiếm thông tin về tên miền

Khi bạn gửi yêu cầu tới facebook.com, máy tính của bạn sẽ tra cứu tên miền để dịch tên miền đó thành địa chỉ IP để máy tính của bạn có thể thực hiện kết nối đó.

Mạng truyền hình Twitter

Mạng truyền hình Twitter

Cái cũ giờ lại mới và cái từng lấp lánh sáng bóng giờ trở nên buồn tẻ. Tôi không nói về việc quần jean JNCO đang trở lại trong giới trẻ sành điệu ở trung tâm thành phố cùng với các mốt cuối thập niên 1990 khác.