diff --git a/docs/src/main/asciidoc/_configprops.adoc b/docs/src/main/asciidoc/_configprops.adoc index e0eac99b..d4d2f86d 100644 --- a/docs/src/main/asciidoc/_configprops.adoc +++ b/docs/src/main/asciidoc/_configprops.adoc @@ -33,7 +33,7 @@ |spring.cloud.consul.discovery.health-check-url | | Custom health check url to override default. |spring.cloud.consul.discovery.heartbeat.enabled | false | |spring.cloud.consul.discovery.heartbeat.interval-ratio | | -|spring.cloud.consul.discovery.heartbeat.ttl | 30s | +|spring.cloud.consul.discovery.heartbeat.ttl | 30s | |spring.cloud.consul.discovery.hostname | | Hostname to use when accessing server. |spring.cloud.consul.discovery.include-hostname-in-instance-id | false | Whether hostname is included into the default instance id when registering service. |spring.cloud.consul.discovery.instance-group | | Service instance group. @@ -75,4 +75,4 @@ |spring.cloud.consul.tls.key-store-password | | Password to an external keystore. |spring.cloud.consul.tls.key-store-path | | Path to an external keystore. -|=== \ No newline at end of file +|=== diff --git a/docs/src/main/asciidoc/spring-cloud-consul.adoc b/docs/src/main/asciidoc/spring-cloud-consul.adoc index 73c3bab7..8215f227 100644 --- a/docs/src/main/asciidoc/spring-cloud-consul.adoc +++ b/docs/src/main/asciidoc/spring-cloud-consul.adoc @@ -31,7 +31,7 @@ To activate Consul Service Discovery use the starter with group `org.springframe === Registering with Consul -When a client registers with Consul, it provides meta-data about itself such as host and port, id, name and tags. An HTTP https://www.consul.io/docs/agent/checks.html[Check] is created by default that Consul hits the `/health` endpoint every 10 seconds. If the health check fails, the service instance is marked as critical. +When a client registers with Consul, it provides meta-data about itself such as host and port, id, name and tags. An HTTP https://www.consul.io/docs/agent/checks.html[Check] is created by default that Consul hits the `/actuator/health` endpoint every 10 seconds. If the health check fails, the service instance is marked as critical. Example Consul client: @@ -149,9 +149,13 @@ spring.cloud.consul.discovery.management-suffix spring.cloud.consul.discovery.management-tags ---- -=== HTTP Health Check +==== HTTP Health Check -The health check for a Consul instance defaults to "/health", which is the default locations of a useful endpoint in a Spring Boot Actuator application. You need to change these, even for an Actuator application if you use a non-default context path or servlet path (e.g. `server.servletPath=/foo`) or management endpoint path (e.g. `management.server.servlet.context-path=/admin`). The interval that Consul uses to check the health endpoint may also be configured. "10s" and "1m" represent 10 seconds and 1 minute respectively. Example: +The health check for a Consul instance defaults to "/actuator/health", which is the default location of the health endpoint in a Spring Boot Actuator application. You need to change this, even for an Actuator application, if you use a non-default context path or servlet path (e.g. `server.servletPath=/foo`) or management endpoint path (e.g. `management.server.servlet.context-path=/admin`). + +The interval that Consul uses to check the health endpoint may also be configured. "10s" and "1m" represent 10 seconds and 1 minute respectively. + +This example illustrates the above (see the `spring.cloud.consul.discovery.health-check-*` properties in link:appendix.html[the appendix page] for more options). .application.yml ---- @@ -159,11 +163,57 @@ spring: cloud: consul: discovery: - healthCheckPath: ${management.server.servlet.context-path}/health + healthCheckPath: ${management.server.servlet.context-path}/actuator/health healthCheckInterval: 15s ---- -You can disable the health check by setting `management.health.consul.enabled=false`. +You can disable the HTTP health check entirely by setting `spring.cloud.consul.discovery.register-health-check=false`. + +===== Applying Headers +Headers can be applied to health check requests. For example, if you're trying to register a https://cloud.spring.io/spring-cloud-config/[Spring Cloud Config] server that uses https://github.com/spring-cloud/spring-cloud-config/blob/master/docs/src/main/asciidoc/spring-cloud-config.adoc#vault-backend[Vault Backend]: + +.application.yml +---- +spring: + cloud: + consul: + discovery: + health-check-headers: + X-Config-Token: 6442e58b-d1ea-182e-cfa5-cf9cddef0722 +---- + +According to the HTTP standard, each header can have more than one values, in which case, an array can be supplied: + +.application.yml +---- +spring: + cloud: + consul: + discovery: + health-check-headers: + X-Config-Token: + - "6442e58b-d1ea-182e-cfa5-cf9cddef0722" + - "Some other value" +---- + +==== Actuator Health Indicator(s) +If the service instance is a Spring Boot Actuator application, it may be provided the following Actuator health indicators. + +===== DiscoveryClientHealthIndicator +When Consul Service Discovery is active, a https://cloud.spring.io/spring-cloud-commons/2.2.x/reference/html/#health-indicator[DiscoverClientHealthIndicator] is configured and made available to the Actuator health endpoint. +See https://cloud.spring.io/spring-cloud-commons/2.2.x/reference/html/#health-indicator[here] for configuration options. + +===== ConsulHealthIndicator +An indicator is configured that verifies the health of the `ConsulClient`. + +By default, it retrieves the Consul leader node status and all registered services. +In deployments that have many registered services it may be costly to retrieve all services on every health check. +To skip the service retrieval and only check the leader node status set `spring.cloud.consul.health-indicator.include-services-query=false`. + +To disable the indicator set `management.health.consul.enabled=false`. + +WARNING: When the application runs in https://cloud.spring.io/spring-cloud-commons/2.2.x/reference/html/#the-bootstrap-application-context[bootstrap context mode] (the default), +this indicator is loaded into the bootstrap context and is not made available to the Actuator health endpoint. ==== Metadata @@ -218,34 +268,6 @@ spring: With this metadata, and multiple service instances deployed on localhost, the random value will kick in there to make the instance unique. In Cloudfoundry the `vcap.application.instance_id` will be populated automatically in a Spring Boot application, so the random value will not be needed. -==== Applying Headers to Health Check Requests - -Headers can be applied to health check requests. For example, if you're trying to register a https://cloud.spring.io/spring-cloud-config/[Spring Cloud Config] server that uses https://github.com/spring-cloud/spring-cloud-config/blob/master/docs/src/main/asciidoc/spring-cloud-config.adoc#vault-backend[Vault Backend]: - -.application.yml ----- -spring: - cloud: - consul: - discovery: - health-check-headers: - X-Config-Token: 6442e58b-d1ea-182e-cfa5-cf9cddef0722 ----- - -According to the HTTP standard, each header can have more than one values, in which case, an array can be supplied: - -.application.yml ----- -spring: - cloud: - consul: - discovery: - health-check-headers: - X-Config-Token: - - "6442e58b-d1ea-182e-cfa5-cf9cddef0722" - - "Some other value" ----- - === Looking up services ==== Using Load-balancer diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulAutoConfiguration.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulAutoConfiguration.java index 827e8710..a9132ee7 100644 --- a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulAutoConfiguration.java +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulAutoConfiguration.java @@ -73,6 +73,7 @@ public class ConsulAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Endpoint.class) + @EnableConfigurationProperties(ConsulHealthIndicatorProperties.class) protected static class ConsulHealthConfig { @Bean @@ -85,8 +86,9 @@ public class ConsulAutoConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnEnabledHealthIndicator("consul") - public ConsulHealthIndicator consulHealthIndicator(ConsulClient consulClient) { - return new ConsulHealthIndicator(consulClient); + public ConsulHealthIndicator consulHealthIndicator(ConsulClient consulClient, + ConsulHealthIndicatorProperties properties) { + return new ConsulHealthIndicator(consulClient, properties); } } diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicator.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicator.java index 3919db11..086e48b3 100644 --- a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicator.java +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicator.java @@ -34,16 +34,24 @@ public class ConsulHealthIndicator extends AbstractHealthIndicator { private ConsulClient consul; - public ConsulHealthIndicator(ConsulClient consul) { + private ConsulHealthIndicatorProperties properties; + + public ConsulHealthIndicator(ConsulClient consul, + ConsulHealthIndicatorProperties properties) { this.consul = consul; + this.properties = properties; } @Override - protected void doHealthCheck(Health.Builder builder) throws Exception { + protected void doHealthCheck(Health.Builder builder) { final Response leaderStatus = this.consul.getStatusLeader(); - final Response>> services = this.consul - .getCatalogServices(CatalogServicesRequest.newBuilder().setQueryParams(QueryParams.DEFAULT).build()); - builder.up().withDetail("leader", leaderStatus.getValue()).withDetail("services", services.getValue()); + builder.up().withDetail("leader", leaderStatus.getValue()); + if (properties.isIncludeServicesQuery()) { + final Response>> services = this.consul + .getCatalogServices(CatalogServicesRequest.newBuilder() + .setQueryParams(QueryParams.DEFAULT).build()); + builder.withDetail("services", services.getValue()); + } } } diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicatorProperties.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicatorProperties.java new file mode 100644 index 00000000..d9e4daf8 --- /dev/null +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicatorProperties.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013-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 + * + * https://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.springframework.cloud.consul; + +import com.ecwid.consul.v1.ConsulClient; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.style.ToStringCreator; + +/** + * Configuration properties for {@link ConsulHealthIndicator}. + * + * @author Chris Bono + */ +@ConfigurationProperties("spring.cloud.consul.health-indicator") +public class ConsulHealthIndicatorProperties { + + /** + * Whether or not the indicator should include a query for all registered services + * during its execution. When set to {@code false} the indicator only uses the lighter + * {@link ConsulClient#getStatusLeader()}. This can be helpful in large deployments + * where the number of services returned makes the operation unnecessarily heavy. + */ + private boolean includeServicesQuery = true; + + boolean isIncludeServicesQuery() { + return includeServicesQuery; + } + + void setIncludeServicesQuery(boolean includeServicesQuery) { + this.includeServicesQuery = includeServicesQuery; + } + + @Override + public String toString() { + return new ToStringCreator(this) + .append("includeServicesQuery", this.includeServicesQuery).toString(); + } + +} diff --git a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulAutoConfigurationTests.java b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulAutoConfigurationTests.java index db571766..2965485e 100644 --- a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulAutoConfigurationTests.java +++ b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulAutoConfigurationTests.java @@ -22,44 +22,105 @@ import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.ConsulRawClient; import com.ecwid.consul.v1.catalog.CatalogConsulClient; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.consul.test.ConsulTestcontainers; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; -@RunWith(SpringRunner.class) -@SpringBootTest(properties = { "spring.cloud.consul.tls.key-store-instance-type=JKS", - "spring.cloud.consul.tls.key-store-path=src/test/resources/server.jks", - "spring.cloud.consul.tls.key-store-password=letmein", - "spring.cloud.consul.tls.certificate-path=src/test/resources/trustStore.jks", - "spring.cloud.consul.tls.certificate-password=change_me" }) -@ContextConfiguration(initializers = ConsulTestcontainers.class) +/** + * Auto-configuration integration tests for {@link ConsulAutoConfiguration}. + * + * @author Chris Bono + */ public class ConsulAutoConfigurationTests { - @Autowired - private ConsulClient consulClient; + private final ApplicationContextRunner appContextRunner = new ApplicationContextRunner() + .withInitializer(new ConsulTestcontainers()) + .withConfiguration(AutoConfigurations.of(ConsulAutoConfiguration.class)); + + @Test + public void defaultConfiguration() { + appContextRunner.run(context -> assertThat(context).hasNotFailed() + .hasSingleBean(ConsulProperties.class).hasSingleBean(ConsulClient.class) + .hasSingleBean(ConsulHealthIndicator.class) + .doesNotHaveBean(ConsulEndpoint.class)); + } + + @Test + public void consulDisabled() { + appContextRunner.withPropertyValues("spring.cloud.consul.enabled=false") + .run(context -> assertThat(context).hasNotFailed() + .doesNotHaveBean(ConsulProperties.class) + .doesNotHaveBean(ConsulClient.class) + .doesNotHaveBean(ConsulHealthIndicator.class) + .doesNotHaveBean(ConsulEndpoint.class)); + } @Test public void tlsConfigured() { - CatalogConsulClient client = (CatalogConsulClient) ReflectionTestUtils.getField(this.consulClient, - "catalogClient"); - ConsulRawClient rawClient = (ConsulRawClient) ReflectionTestUtils.getField(client, "rawClient"); - HttpTransport httpTransport = (HttpTransport) ReflectionTestUtils.getField(rawClient, "httpTransport"); - assertThat(httpTransport).isInstanceOf(DefaultHttpsTransport.class); + appContextRunner.withPropertyValues( + "spring.cloud.consul.tls.key-store-instance-type=JKS", + "spring.cloud.consul.tls.key-store-path=src/test/resources/server.jks", + "spring.cloud.consul.tls.key-store-password=letmein", + "spring.cloud.consul.tls.certificate-path=src/test/resources/trustStore.jks", + "spring.cloud.consul.tls.certificate-password=change_me").run(context -> { + assertThat(context).hasNotFailed().hasSingleBean(ConsulClient.class); + + ConsulClient consulClient = context.getBean(ConsulClient.class); + CatalogConsulClient client = (CatalogConsulClient) ReflectionTestUtils.getField(consulClient, + "catalogClient"); + ConsulRawClient rawClient = (ConsulRawClient) ReflectionTestUtils.getField(client, "rawClient"); + HttpTransport httpTransport = (HttpTransport) ReflectionTestUtils.getField(rawClient, "httpTransport"); + assertThat(httpTransport).isInstanceOf(DefaultHttpsTransport.class); + }); } - @EnableAutoConfiguration - @SpringBootConfiguration - protected static class TestConfig { + @Test + public void nonActuatorAppGetsNoEndpointOrHealthIndicator() { + appContextRunner.withClassLoader(new FilteredClassLoader(Endpoint.class)) + .withPropertyValues("management.endpoints.web.exposure.include=consul") + .run(context -> assertThat(context).hasNotFailed() + .doesNotHaveBean(ConsulHealthIndicator.class) + .doesNotHaveBean(ConsulEndpoint.class)); + } + @Test + public void consulEndpointAvailable() { + appContextRunner + .withPropertyValues("management.endpoints.web.exposure.include=consul") + .run(context -> assertThat(context).hasNotFailed() + .hasSingleBean(ConsulEndpoint.class)); + } + + @Test + public void consulEndpointAvailableButDisabled() { + appContextRunner + .withPropertyValues("management.endpoints.web.exposure.include=consul", + "management.endpoint.consul.enabled=false") + .run(context -> assertThat(context).hasNotFailed() + .doesNotHaveBean(ConsulEndpoint.class)); + } + + @Test + public void consulEndpointDisabled() { + appContextRunner.withPropertyValues("spring.cloud.consul.enabled=false") + .run(context -> assertThat(context).hasNotFailed() + .doesNotHaveBean(ConsulProperties.class) + .doesNotHaveBean(ConsulClient.class) + .doesNotHaveBean(ConsulHealthIndicator.class) + .doesNotHaveBean(ConsulEndpoint.class)); + } + + @Test + public void consulHealthIndicatorDisabled() { + appContextRunner.withPropertyValues("management.health.consul.enabled=false") + .run(context -> assertThat(context).hasNotFailed() + .doesNotHaveBean(ConsulHealthIndicator.class)); } } diff --git a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorDownTest.java b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorDownTest.java index b84c487a..25d471b6 100644 --- a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorDownTest.java +++ b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorDownTest.java @@ -16,6 +16,9 @@ package org.springframework.cloud.consul; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.catalog.CatalogServicesRequest; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,23 +28,47 @@ import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.Status; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; /** + * Integration test for {@link ConsulHealthIndicator} when its in the DOWN status. + * * @author Lomesh Patel (lomeshpatel) */ @RunWith(SpringRunner.class) -@SpringBootTest(properties = "spring.cloud.consul.host=invalidhost") +@SpringBootTest public class ConsulHealthIndicatorDownTest { + @MockBean + private ConsulClient consulClient; + @Autowired private HealthEndpoint healthEndpoint; @Test - public void doHealthCheck() { - assertThat(this.healthEndpoint.health().getStatus()).as("health status was not DOWN").isEqualTo(Status.DOWN); + public void statusIsDownWhenConsulClientFailsToGetLeaderStatus() { + when(consulClient.getStatusLeader()).thenThrow(new RuntimeException("no leader")); + assertThat(this.healthEndpoint.health().getStatus()) + .as("health status was not DOWN").isEqualTo(Status.DOWN); + verify(consulClient).getStatusLeader(); + } + + @Test + public void statusIsDownWhenConsulClientFailsToGetServices() { + Response leaderStatus = new Response<>("OK", 5150L, true, + System.currentTimeMillis()); + when(consulClient.getStatusLeader()).thenReturn(leaderStatus); + when(consulClient.getCatalogServices(any(CatalogServicesRequest.class))) + .thenThrow(new RuntimeException("no services")); + assertThat(this.healthEndpoint.health().getStatus()) + .as("health status was not DOWN").isEqualTo(Status.DOWN); + verify(consulClient).getCatalogServices(any(CatalogServicesRequest.class)); } @EnableAutoConfiguration diff --git a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorLightweightUpTest.java b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorLightweightUpTest.java new file mode 100644 index 00000000..7cf1df79 --- /dev/null +++ b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorLightweightUpTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013-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 + * + * https://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.springframework.cloud.consul; + +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.catalog.CatalogServicesRequest; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.actuate.health.HealthEndpoint; +import org.springframework.boot.actuate.health.Status; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.cloud.consul.test.ConsulTestcontainers; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +/** + * Integration test for {@link ConsulHealthIndicator} using its lightweight check when its + * in the UP status. + * + * @author Lomesh Patel (lomeshpatel) + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + properties = "spring.cloud.consul.health-indicator.include-services-query=false") +@ContextConfiguration(initializers = ConsulTestcontainers.class) +public class ConsulHealthIndicatorLightweightUpTest { + + @SpyBean + private ConsulClient consulClient; + + @Autowired + private HealthEndpoint healthEndpoint; + + @Test + public void statusIsUp() { + assertThat(this.healthEndpoint.health().getStatus()) + .as("health status was not UP").isEqualTo(Status.UP); + verify(consulClient).getStatusLeader(); + verify(consulClient, never()) + .getCatalogServices(any(CatalogServicesRequest.class)); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + protected static class TestConfig { + + } + +} diff --git a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorUpTest.java b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorUpTest.java index 087b06db..a4716e62 100644 --- a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorUpTest.java +++ b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorUpTest.java @@ -16,6 +16,8 @@ package org.springframework.cloud.consul; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.catalog.CatalogServicesRequest; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,13 +27,18 @@ import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.Status; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.cloud.consul.test.ConsulTestcontainers; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; /** + * Integration test for {@link ConsulHealthIndicator} when its in the UP status. + * * @author Lomesh Patel (lomeshpatel) */ @RunWith(SpringRunner.class) @@ -39,12 +46,18 @@ import static org.assertj.core.api.Assertions.assertThat; @ContextConfiguration(initializers = ConsulTestcontainers.class) public class ConsulHealthIndicatorUpTest { + @SpyBean + private ConsulClient consulClient; + @Autowired private HealthEndpoint healthEndpoint; @Test - public void doHealthCheck() { - assertThat(this.healthEndpoint.health().getStatus()).as("health status was not UP").isEqualTo(Status.UP); + public void statusIsUp() { + assertThat(this.healthEndpoint.health().getStatus()) + .as("health status was not UP").isEqualTo(Status.UP); + verify(consulClient).getStatusLeader(); + verify(consulClient).getCatalogServices(any(CatalogServicesRequest.class)); } @EnableAutoConfiguration