de.codecentric.boot.admin.server.services.endpoints.QueryIndexEndpointStrategyTest.java Source code

Java tutorial

Introduction

Here is the source code for de.codecentric.boot.admin.server.services.endpoints.QueryIndexEndpointStrategyTest.java

Source

/*
 * Copyright 2014-2019 the original author or authors.
 *
 * 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 de.codecentric.boot.admin.server.services.endpoints;

import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.values.Endpoint;
import de.codecentric.boot.admin.server.domain.values.Endpoints;
import de.codecentric.boot.admin.server.domain.values.InstanceId;
import de.codecentric.boot.admin.server.domain.values.Registration;
import de.codecentric.boot.admin.server.web.client.InstanceWebClient;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import reactor.netty.http.client.HttpClient;
import reactor.test.StepVerifier;

import java.time.Duration;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import com.github.tomakehurst.wiremock.http.Fault;
import com.github.tomakehurst.wiremock.junit.WireMockRule;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.anyRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.notFound;
import static com.github.tomakehurst.wiremock.client.WireMock.ok;
import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED;
import static de.codecentric.boot.admin.server.web.client.InstanceExchangeFilterFunctions.retry;
import static de.codecentric.boot.admin.server.web.client.InstanceExchangeFilterFunctions.rewriteEndpointUrl;
import static de.codecentric.boot.admin.server.web.client.InstanceExchangeFilterFunctions.timeout;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;

public class QueryIndexEndpointStrategyTest {

    @Rule
    public WireMockRule wireMock = new WireMockRule(wireMockConfig().dynamicPort().dynamicHttpsPort());

    private InstanceWebClient instanceWebClient = InstanceWebClient.builder()
            .webClient(WebClient.builder().clientConnector(httpConnector())).filter(rewriteEndpointUrl())
            .filter(retry(0, singletonMap(Endpoint.ACTUATOR_INDEX, 1)))
            .filter(timeout(Duration.ofSeconds(1), emptyMap())).build();

    @Test
    public void should_return_endpoints() {
        //given
        Instance instance = Instance.create(InstanceId.of("id"))
                .register(Registration.create("test", this.wireMock.url("/mgmt/health"))
                        .managementUrl(this.wireMock.url("/mgmt")).build());

        String host = "https://localhost:" + this.wireMock.httpsPort();
        String body = "{\"_links\":{\"metrics-requiredMetricName\":{\"templated\":true,\"href\":\"" + host
                + "/mgmt/metrics/{requiredMetricName}\"},\"self\":{\"templated\":false,\"href\":\"" + host
                + "/mgmt\"},\"metrics\":{\"templated\":false,\"href\":\"" + host
                + "/mgmt/stats\"},\"info\":{\"templated\":false,\"href\":\"" + host + "/mgmt/info\"}}}";

        this.wireMock
                .stubFor(get("/mgmt").willReturn(ok(body).withHeader("Content-Type", ActuatorMediaType.V2_JSON)));

        QueryIndexEndpointStrategy strategy = new QueryIndexEndpointStrategy(this.instanceWebClient);

        //when
        StepVerifier.create(strategy.detectEndpoints(instance))
                //then
                .expectNext(
                        Endpoints.single("metrics", host + "/mgmt/stats").withEndpoint("info", host + "/mgmt/info"))//
                .verifyComplete();
    }

    @Test
    public void should_return_endpoints_with_aligned_scheme() {
        //given
        Instance instance = Instance.create(InstanceId.of("id"))
                .register(Registration.create("test", this.wireMock.url("/mgmt/health"))
                        .managementUrl(this.wireMock.url("/mgmt")).build());

        String host = "http://localhost:" + this.wireMock.httpsPort();
        String body = "{\"_links\":{\"metrics-requiredMetricName\":{\"templated\":true,\"href\":\"" + host
                + "/mgmt/metrics/{requiredMetricName}\"},\"self\":{\"templated\":false,\"href\":\"" + host
                + "/mgmt\"},\"metrics\":{\"templated\":false,\"href\":\"" + host
                + "/mgmt/stats\"},\"info\":{\"templated\":false,\"href\":\"" + host + "/mgmt/info\"}}}";

        this.wireMock
                .stubFor(get("/mgmt").willReturn(ok(body).withHeader("Content-Type", ActuatorMediaType.V2_JSON)));

        QueryIndexEndpointStrategy strategy = new QueryIndexEndpointStrategy(this.instanceWebClient);

        //when
        String secureHost = "https://localhost:" + this.wireMock.httpsPort();
        StepVerifier.create(strategy.detectEndpoints(instance))
                //then
                .expectNext(Endpoints.single("metrics", secureHost + "/mgmt/stats").withEndpoint("info",
                        secureHost + "/mgmt/info"))//
                .verifyComplete();
    }

    @Test
    public void should_return_empty_on_empty_endpoints() {
        //given
        Instance instance = Instance.create(InstanceId.of("id"))
                .register(Registration.create("test", this.wireMock.url("/mgmt/health"))
                        .managementUrl(this.wireMock.url("/mgmt")).build());

        String body = "{\"_links\":{}}";
        this.wireMock.stubFor(
                get("/mgmt").willReturn(okJson(body).withHeader("Content-Type", ActuatorMediaType.V2_JSON)));

        QueryIndexEndpointStrategy strategy = new QueryIndexEndpointStrategy(this.instanceWebClient);

        //when
        StepVerifier.create(strategy.detectEndpoints(instance))
                //then
                .verifyComplete();
    }

    @Test
    public void should_return_empty_on_not_found() {
        //given
        Instance instance = Instance.create(InstanceId.of("id"))
                .register(Registration.create("test", this.wireMock.url("/mgmt/health"))
                        .managementUrl(this.wireMock.url("/mgmt")).build());

        this.wireMock.stubFor(get("/mgmt").willReturn(notFound()));

        QueryIndexEndpointStrategy strategy = new QueryIndexEndpointStrategy(this.instanceWebClient);

        //when
        StepVerifier.create(strategy.detectEndpoints(instance))
                //then
                .verifyComplete();
    }

    @Test
    public void should_return_empty_on_error() {
        //given
        Instance instance = Instance.create(InstanceId.of("id"))
                .register(Registration.create("test", this.wireMock.url("/mgmt/health"))
                        .managementUrl(this.wireMock.url("/mgmt")).build());

        this.wireMock.stubFor(get("/mgmt").willReturn(aResponse().withFault(Fault.EMPTY_RESPONSE)));

        QueryIndexEndpointStrategy strategy = new QueryIndexEndpointStrategy(this.instanceWebClient);

        //when
        StepVerifier.create(strategy.detectEndpoints(instance))
                //then
                .verifyComplete();
    }

    @Test
    public void should_return_empty_on_wrong_content_type() {
        //given
        Instance instance = Instance.create(InstanceId.of("id"))
                .register(Registration.create("test", this.wireMock.url("/mgmt/health"))
                        .managementUrl(this.wireMock.url("/mgmt")).build());

        String body = "HELLOW WORLD";
        this.wireMock
                .stubFor(get("/mgmt").willReturn(ok(body).withHeader("Content-Type", MediaType.TEXT_PLAIN_VALUE)));

        QueryIndexEndpointStrategy strategy = new QueryIndexEndpointStrategy(this.instanceWebClient);

        //when
        StepVerifier.create(strategy.detectEndpoints(instance))
                //then
                .verifyComplete();
    }

    @Test
    public void should_return_empty_when_mgmt_equals_service_url() {
        //given
        Instance instance = Instance.create(InstanceId.of("id"))
                .register(Registration.create("test", this.wireMock.url("/app/health"))
                        .managementUrl(this.wireMock.url("/app")).serviceUrl(this.wireMock.url("/app")).build());

        QueryIndexEndpointStrategy strategy = new QueryIndexEndpointStrategy(this.instanceWebClient);

        //when/then
        StepVerifier.create(strategy.detectEndpoints(instance)).verifyComplete();
        this.wireMock.verify(0, anyRequestedFor(urlPathEqualTo("/app")));
    }

    @Test
    public void should_retry() {
        //given
        Instance instance = Instance.create(InstanceId.of("id"))
                .register(Registration.create("test", this.wireMock.url("/mgmt/health"))
                        .managementUrl(this.wireMock.url("/mgmt")).build());

        String body = "{\"_links\":{\"metrics-requiredMetricName\":{\"templated\":true,\"href\":\"/mgmt/metrics/{requiredMetricName}\"},\"self\":{\"templated\":false,\"href\":\"/mgmt\"},\"metrics\":{\"templated\":false,\"href\":\"/mgmt/stats\"},\"info\":{\"templated\":false,\"href\":\"/mgmt/info\"}}}";

        this.wireMock.stubFor(get("/mgmt").inScenario("retry").whenScenarioStateIs(STARTED)
                .willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER)).willSetStateTo("recovered"));

        this.wireMock.stubFor(get("/mgmt").inScenario("retry").whenScenarioStateIs("recovered")
                .willReturn(ok(body).withHeader("Content-Type", ActuatorMediaType.V2_JSON)));

        QueryIndexEndpointStrategy strategy = new QueryIndexEndpointStrategy(this.instanceWebClient);

        //when
        StepVerifier.create(strategy.detectEndpoints(instance))
                //then
                .expectNext(Endpoints.single("metrics", "/mgmt/stats").withEndpoint("info", "/mgmt/info"))//
                .verifyComplete();
    }

    private ReactorClientHttpConnector httpConnector() {
        SslContextBuilder sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE);
        HttpClient client = HttpClient.create().secure(ssl -> ssl.sslContext(sslCtx));
        return new ReactorClientHttpConnector(client);
    }
}