Make Health and Status immutable

Update Health and Status objects to be immutable, update the existing
builder methods to return new instances and add static convenience
methods to Health.
pull/944/head
Phillip Webb 11 years ago
parent 660d9e24dc
commit aa03d9a41c

@ -17,6 +17,7 @@
package org.springframework.boot.actuate.health; package org.springframework.boot.actuate.health;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -31,21 +32,21 @@ public abstract class AbstractHealthAggregator implements HealthAggregator {
@Override @Override
public final Health aggregate(Map<String, Health> healths) { public final Health aggregate(Map<String, Health> healths) {
Health health = new Health(); List<Status> statusCandidates = new ArrayList<Status>();
List<Status> status = new ArrayList<Status>(); Map<String, Object> details = new LinkedHashMap<String, Object>();
for (Map.Entry<String, Health> entry : healths.entrySet()) { for (Map.Entry<String, Health> entry : healths.entrySet()) {
health.withDetail(entry.getKey(), entry.getValue()); details.put(entry.getKey(), entry.getValue());
status.add(entry.getValue().getStatus()); statusCandidates.add(entry.getValue().getStatus());
} }
health.status(aggregateStatus(status)); return new Health(aggregateStatus(statusCandidates), details);
return health;
} }
/** /**
* Actual aggregation logic. * Return the single 'aggregate' status that should be used from the specified
* @param status list of given {@link Status} instances to aggregate * candidates.
* @return aggregated {@link Status} * @param candidates
* @return a single status
*/ */
protected abstract Status aggregateStatus(List<Status> status); protected abstract Status aggregateStatus(List<Status> candidates);
} }

@ -21,7 +21,7 @@ package org.springframework.boot.actuate.health;
* {@link Health} instance and error handling. * {@link Health} instance and error handling.
* <p> * <p>
* This implementation is only suitable if an {@link Exception} raised from * This implementation is only suitable if an {@link Exception} raised from
* {@link #doHealthCheck(Health)} should create a {@link Status#DOWN} health status. * {@link #doHealthCheck()} should create a {@link Status#DOWN} health status.
* *
* @author Christian Dupuis * @author Christian Dupuis
* @since 1.1.0 * @since 1.1.0
@ -30,21 +30,19 @@ public abstract class AbstractHealthIndicator implements HealthIndicator {
@Override @Override
public final Health health() { public final Health health() {
Health health = new Health();
try { try {
doHealthCheck(health); return doHealthCheck();
} }
catch (Exception ex) { catch (Exception ex) {
health.down().withException(ex); return Health.down(ex);
} }
return health;
} }
/** /**
* Actual health check logic. * Actual health check logic.
* @param health {@link Health} instance of report status. * @return the {@link Health}
* @throws Exception any {@link Exception} that should create a {@link Status#DOWN} * @throws Exception any {@link Exception} that should create a {@link Status#DOWN}
* system status. * system status.
*/ */
protected abstract void doHealthCheck(Health health) throws Exception; protected abstract Health doHealthCheck() throws Exception;
} }

@ -16,11 +16,11 @@
package org.springframework.boot.actuate.health; package org.springframework.boot.actuate.health;
import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonAnySetter;
@ -29,8 +29,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonUnwrapped; import com.fasterxml.jackson.annotation.JsonUnwrapped;
/** /**
* Value object used to carry information about the health information of a component or * Carries information about the health of a component or subsystem.
* subsystem.
* <p> * <p>
* {@link Health} contains a {@link Status} to express the state of a component or * {@link Health} contains a {@link Status} to express the state of a component or
* subsystem and some additional details to carry some contextual information. * subsystem and some additional details to carry some contextual information.
@ -39,92 +38,162 @@ import com.fasterxml.jackson.annotation.JsonUnwrapped;
* in a {@link HealthIndicator} would be: * in a {@link HealthIndicator} would be:
* *
* <pre class="code"> * <pre class="code">
* Health health = new Health();
* try { * try {
* // do some test to determine state of component * // do some test to determine state of component
* health.up().withDetail(&quot;version&quot;, &quot;1.1.2&quot;); * return Health.up(&quot;version&quot;, &quot;1.1.2&quot;);
* } * }
* catch (Exception ex) { * catch (Exception ex) {
* health.down().withException(ex); * return Health.down(ex);
* } * }
* return health;
* </pre> * </pre>
* *
* @author Christian Dupuis * @author Christian Dupuis
* @author Phillip Webb
* @since 1.1.0 * @since 1.1.0
*/ */
@JsonInclude(Include.NON_EMPTY) @JsonInclude(Include.NON_EMPTY)
public class Health { public final class Health {
private Status status; private static final Map<String, Object> NO_DETAILS = Collections
.<String, Object> emptyMap();
private Map<String, Object> details; private final Status status;
public Health() { private final Map<String, Object> details;
this(Status.UNKNOWN);
}
public Health(Status status) { /**
* Create a new {@link Health} instance with the specified status and details.
* @param status the status
* @param details the details or {@code null}
*/
public Health(Status status, Map<String, ?> details) {
Assert.notNull(status, "Status must not be null");
this.status = status; this.status = status;
this.details = new LinkedHashMap<String, Object>(); this.details = Collections.unmodifiableMap(details == null ? NO_DETAILS
: new LinkedHashMap<String, Object>(details));
} }
public Health status(Status status) { /**
Assert.notNull(status, "Status must not be null"); * @return the status of the health (never {@code null})
this.status = status; */
return this; @JsonUnwrapped
public Status getStatus() {
return this.status;
} }
public Health up() { /**
return status(Status.UP); * @return the details of the health or an empty map.
*/
@JsonAnyGetter
public Map<String, Object> getDetails() {
return this.details;
} }
public Health down() { @Override
return status(Status.DOWN); public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj != null && obj instanceof Health) {
Health other = (Health) obj;
return this.status.equals(other.status) && this.details.equals(other.details);
}
return false;
}
@Override
public int hashCode() {
int hashCode = this.status.hashCode();
return 13 * hashCode + this.details.hashCode();
}
@Override
public String toString() {
return getStatus() + " " + getDetails();
} }
/**
* Create a new {@link Health} object from this one, containing an additional
* exception detail.
* @param ex the exception
* @return a new {@link Health} instance
*/
public Health withException(Exception ex) { public Health withException(Exception ex) {
Assert.notNull(ex, "Exception must not be null"); Assert.notNull(ex, "Exception must not be null");
return withDetail("error", ex.getClass().getName() + ": " + ex.getMessage()); return withDetail("error", ex.getClass().getName() + ": " + ex.getMessage());
} }
/**
* Create a new {@link Health} object from this one, containing an additional detail.
* @param key the detail key
* @param data the detail data
* @return a new {@link Health} instance
*/
@JsonAnySetter @JsonAnySetter
public Health withDetail(String key, Object data) { public Health withDetail(String key, Object data) {
Assert.notNull(key, "Key must not be null"); Assert.notNull(key, "Key must not be null");
Assert.notNull(data, "Data must not be null"); Assert.notNull(data, "Data must not be null");
this.details.put(key, data); Map<String, Object> details = new LinkedHashMap<String, Object>(this.details);
return this; details.put(key, data);
return new Health(this.status, details);
} }
@JsonUnwrapped /**
public Status getStatus() { * Create a new {@link Health} instance with an {@link Status#UNKNOWN} status.
return this.status; * @return a new {@link Health} instance
*/
public static Health unknown() {
return status(Status.UNKNOWN);
} }
@JsonAnyGetter /**
public Map<String, Object> getDetails() { * Create a new {@link Health} instance with an {@link Status#UP} status.
return this.details; * @return a new {@link Health} instance
*/
public static Health up() {
return status(Status.UP);
} }
@Override /**
public boolean equals(Object obj) { * Create a new {@link Health} instance with an {@link Status#DOWN} status an the
if (obj == this) { * specified exception details.
return true; * @param ex the exception
* @return a new {@link Health} instance
*/
public static Health down(Exception ex) {
return down().withException(ex);
} }
if (obj != null && obj instanceof Health) {
return ObjectUtils.nullSafeEquals(this.status, ((Health) obj).status) /**
&& ObjectUtils.nullSafeEquals(this.details, ((Health) obj).details); * Create a new {@link Health} instance with a {@link Status#DOWN} status.
* @return a new {@link Health} instance
*/
public static Health down() {
return status(Status.DOWN);
} }
return false;
/**
* Create a new {@link Health} instance with an {@link Status#OUT_OF_SERVICE} status.
* @return a new {@link Health} instance
*/
public static Health outOfService() {
return status(Status.OUT_OF_SERVICE);
} }
@Override /**
public int hashCode() { * Create a new {@link Health} instance with a specific status code.
int hashCode = 0; * @return a new {@link Health} instance
if (this.status != null) { */
hashCode = this.status.hashCode(); public static Health status(String statusCode) {
return status(new Status(statusCode));
} }
return 13 * hashCode + this.details.hashCode();
/**
* Create a new {@link Health} instance with a specific {@link Status}.
* @return a new {@link Health} instance
*/
public static Health status(Status status) {
return new Health(status, null);
} }
} }

@ -38,9 +38,9 @@ public class MongoHealthIndicator extends AbstractHealthIndicator {
} }
@Override @Override
protected void doHealthCheck(Health health) throws Exception { protected Health doHealthCheck() throws Exception {
CommandResult result = this.mongoTemplate.executeCommand("{ serverStatus: 1 }"); CommandResult result = this.mongoTemplate.executeCommand("{ serverStatus: 1 }");
health.up().withDetail("version", result.getString("version")); return Health.up().withDetail("version", result.getString("version"));
} }
} }

@ -66,14 +66,14 @@ public class OrderedHealthAggregator extends AbstractHealthAggregator {
} }
@Override @Override
protected Status aggregateStatus(List<Status> status) { protected Status aggregateStatus(List<Status> candidates) {
// If no status is given return UNKNOWN // If no status is given return UNKNOWN
if (status.size() == 0) { if (candidates.size() == 0) {
return Status.UNKNOWN; return Status.UNKNOWN;
} }
// Sort given Status instances by configured order // Sort given Status instances by configured order
Collections.sort(status, new StatusComparator(this.statusOrder)); Collections.sort(candidates, new StatusComparator(this.statusOrder));
return status.get(0); return candidates.get(0);
} }
/** /**

@ -41,17 +41,19 @@ public class RabbitHealthIndicator extends AbstractHealthIndicator {
} }
@Override @Override
protected void doHealthCheck(Health health) throws Exception { protected Health doHealthCheck() throws Exception {
health.up().withDetail("version", return Health.up().withDetail("version", getVersion());
this.rabbitTemplate.execute(new ChannelCallback<String>() { }
private String getVersion() {
return this.rabbitTemplate.execute(new ChannelCallback<String>() {
@Override @Override
public String doInRabbit(Channel channel) throws Exception { public String doInRabbit(Channel channel) throws Exception {
Map<String, Object> serverProperties = channel.getConnection() Map<String, Object> serverProperties = channel.getConnection()
.getServerProperties(); .getServerProperties();
return serverProperties.get("version").toString(); return serverProperties.get("version").toString();
} }
})); });
} }
} }

@ -40,12 +40,12 @@ public class RedisHealthIndicator extends AbstractHealthIndicator {
} }
@Override @Override
protected void doHealthCheck(Health health) throws Exception { protected Health doHealthCheck() throws Exception {
RedisConnection connection = null; RedisConnection connection = RedisConnectionUtils
.getConnection(this.redisConnectionFactory);
try { try {
connection = RedisConnectionUtils.getConnection(this.redisConnectionFactory);
Properties info = connection.info(); Properties info = connection.info();
health.up().withDetail("version", info.getProperty("redis_version")); return Health.up().withDetail("version", info.getProperty("redis_version"));
} }
finally { finally {
RedisConnectionUtils.releaseConnection(connection, RedisConnectionUtils.releaseConnection(connection,

@ -35,7 +35,7 @@ import org.springframework.util.StringUtils;
* @author Dave Syer * @author Dave Syer
* @author Christian Dupuis * @author Christian Dupuis
*/ */
public class SimpleDataSourceHealthIndicator implements HealthIndicator { public class SimpleDataSourceHealthIndicator extends AbstractHealthIndicator {
private DataSource dataSource; private DataSource dataSource;
@ -63,7 +63,6 @@ public class SimpleDataSourceHealthIndicator implements HealthIndicator {
/** /**
* Create a new {@link SimpleDataSourceHealthIndicator} using the specified * Create a new {@link SimpleDataSourceHealthIndicator} using the specified
* datasource. * datasource.
*
* @param dataSource the data source * @param dataSource the data source
*/ */
public SimpleDataSourceHealthIndicator(DataSource dataSource) { public SimpleDataSourceHealthIndicator(DataSource dataSource) {
@ -72,40 +71,39 @@ public class SimpleDataSourceHealthIndicator implements HealthIndicator {
} }
@Override @Override
public Health health() { protected Health doHealthCheck() throws Exception {
Health health = new Health(); if (this.dataSource == null) {
health.up(); return Health.up().withDetail("database", "unknown");
String product = "unknown";
if (this.dataSource != null) {
try {
product = this.jdbcTemplate.execute(new ConnectionCallback<String>() {
@Override
public String doInConnection(Connection connection)
throws SQLException, DataAccessException {
return connection.getMetaData().getDatabaseProductName();
}
});
health.withDetail("database", product);
} }
catch (DataAccessException ex) { return doDataSourceHealthCheck();
health.down().withException(ex);
} }
private Health doDataSourceHealthCheck() throws Exception {
String product = getProduct();
Health health = Health.up().withDetail("database", product);
String query = detectQuery(product); String query = detectQuery(product);
if (StringUtils.hasText(query)) { if (StringUtils.hasText(query)) {
try { try {
health.withDetail("hello", health = health.withDetail("hello",
this.jdbcTemplate.queryForObject(query, Object.class)); this.jdbcTemplate.queryForObject(query, Object.class));
} }
catch (Exception ex) { catch (Exception ex) {
health.down().withException(ex); return Health.down().withDetail("database", product).withException(ex);
}
} }
} }
return health; return health;
} }
private String getProduct() {
return this.jdbcTemplate.execute(new ConnectionCallback<String>() {
@Override
public String doInConnection(Connection connection) throws SQLException,
DataAccessException {
return connection.getMetaData().getDatabaseProductName();
}
});
}
protected String detectQuery(String product) { protected String detectQuery(String product) {
String query = this.query; String query = this.query;
if (!StringUtils.hasText(query)) { if (!StringUtils.hasText(query)) {

@ -33,9 +33,9 @@ public class SolrHealthIndicator extends AbstractHealthIndicator {
} }
@Override @Override
protected void doHealthCheck(Health health) throws Exception { protected Health doHealthCheck() throws Exception {
this.solrServer.ping(); Object status = this.solrServer.ping().getResponse().get("status");
health.up().withDetail("solrStatus", return Health.up().withDetail("solrStatus", status);
this.solrServer.ping().getResponse().get("status"));
} }
} }

@ -35,7 +35,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @since 1.1.0 * @since 1.1.0
*/ */
@JsonInclude(Include.NON_EMPTY) @JsonInclude(Include.NON_EMPTY)
public class Status { public final class Status {
/** /**
* Convenient constant value representing unknown state * Convenient constant value representing unknown state

@ -25,8 +25,8 @@ package org.springframework.boot.actuate.health;
public class VanillaHealthIndicator extends AbstractHealthIndicator { public class VanillaHealthIndicator extends AbstractHealthIndicator {
@Override @Override
protected void doHealthCheck(Health health) throws Exception { protected Health doHealthCheck() throws Exception {
health.up(); return Health.up();
} }
} }

@ -65,7 +65,7 @@ public class HealthEndpointTests extends AbstractEndpointTests<HealthEndpoint> {
@Override @Override
public Health health() { public Health health() {
return new Health().status(new Status("FINE")); return Health.status("FINE");
} }
}; };
} }

@ -51,7 +51,7 @@ public class HealthMvcEndpointTests {
@Test @Test
public void up() { public void up() {
when(this.endpoint.invoke()).thenReturn(new Health().up()); when(this.endpoint.invoke()).thenReturn(Health.up());
Object result = this.mvc.invoke(); Object result = this.mvc.invoke();
assertTrue(result instanceof Health); assertTrue(result instanceof Health);
assertTrue(((Health) result).getStatus() == Status.UP); assertTrue(((Health) result).getStatus() == Status.UP);
@ -60,7 +60,7 @@ public class HealthMvcEndpointTests {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Test @Test
public void down() { public void down() {
when(this.endpoint.invoke()).thenReturn(new Health().down()); when(this.endpoint.invoke()).thenReturn(Health.down());
Object result = this.mvc.invoke(); Object result = this.mvc.invoke();
assertTrue(result instanceof ResponseEntity); assertTrue(result instanceof ResponseEntity);
ResponseEntity<Health> response = (ResponseEntity<Health>) result; ResponseEntity<Health> response = (ResponseEntity<Health>) result;
@ -71,7 +71,7 @@ public class HealthMvcEndpointTests {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Test @Test
public void customMapping() { public void customMapping() {
when(this.endpoint.invoke()).thenReturn(new Health().status(new Status("OK"))); when(this.endpoint.invoke()).thenReturn(Health.status("OK"));
this.mvc.setStatusMapping(Collections.singletonMap("OK", this.mvc.setStatusMapping(Collections.singletonMap("OK",
HttpStatus.INTERNAL_SERVER_ERROR)); HttpStatus.INTERNAL_SERVER_ERROR));
Object result = this.mvc.invoke(); Object result = this.mvc.invoke();

@ -55,9 +55,9 @@ public class CompositeHealthIndicatorTests {
@Before @Before
public void setup() { public void setup() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
given(this.one.health()).willReturn(new Health().withDetail("1", "1")); given(this.one.health()).willReturn(Health.unknown().withDetail("1", "1"));
given(this.two.health()).willReturn(new Health().withDetail("2", "2")); given(this.two.health()).willReturn(Health.unknown().withDetail("2", "2"));
given(this.three.health()).willReturn(new Health().withDetail("3", "3")); given(this.three.health()).willReturn(Health.unknown().withDetail("3", "3"));
this.healthAggregator = new OrderedHealthAggregator(); this.healthAggregator = new OrderedHealthAggregator();
} }
@ -72,9 +72,9 @@ public class CompositeHealthIndicatorTests {
Health result = composite.health(); Health result = composite.health();
assertThat(result.getDetails().size(), equalTo(2)); assertThat(result.getDetails().size(), equalTo(2));
assertThat(result.getDetails(), assertThat(result.getDetails(),
hasEntry("one", (Object) new Health().withDetail("1", "1"))); hasEntry("one", (Object) Health.unknown().withDetail("1", "1")));
assertThat(result.getDetails(), assertThat(result.getDetails(),
hasEntry("two", (Object) new Health().withDetail("2", "2"))); hasEntry("two", (Object) Health.unknown().withDetail("2", "2")));
} }
@Test @Test
@ -88,11 +88,11 @@ public class CompositeHealthIndicatorTests {
Health result = composite.health(); Health result = composite.health();
assertThat(result.getDetails().size(), equalTo(3)); assertThat(result.getDetails().size(), equalTo(3));
assertThat(result.getDetails(), assertThat(result.getDetails(),
hasEntry("one", (Object) new Health().withDetail("1", "1"))); hasEntry("one", (Object) Health.unknown().withDetail("1", "1")));
assertThat(result.getDetails(), assertThat(result.getDetails(),
hasEntry("two", (Object) new Health().withDetail("2", "2"))); hasEntry("two", (Object) Health.unknown().withDetail("2", "2")));
assertThat(result.getDetails(), assertThat(result.getDetails(),
hasEntry("three", (Object) new Health().withDetail("3", "3"))); hasEntry("three", (Object) Health.unknown().withDetail("3", "3")));
} }
@Test @Test
@ -104,9 +104,9 @@ public class CompositeHealthIndicatorTests {
Health result = composite.health(); Health result = composite.health();
assertThat(result.getDetails().size(), equalTo(2)); assertThat(result.getDetails().size(), equalTo(2));
assertThat(result.getDetails(), assertThat(result.getDetails(),
hasEntry("one", (Object) new Health().withDetail("1", "1"))); hasEntry("one", (Object) Health.unknown().withDetail("1", "1")));
assertThat(result.getDetails(), assertThat(result.getDetails(),
hasEntry("two", (Object) new Health().withDetail("2", "2"))); hasEntry("two", (Object) Health.unknown().withDetail("2", "2")));
} }
@Test @Test

@ -0,0 +1,156 @@
/*
* Copyright 2012-2014 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 org.springframework.boot.actuate.health;
import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link Health}.
*
* @author Phillip Webb
*/
public class HealthTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void statusMustNotBeNull() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Status must not be null");
new Health(null, null);
}
@Test
public void createWithStatus() throws Exception {
Health health = new Health(Status.UP, null);
assertThat(health.getStatus(), equalTo(Status.UP));
assertThat(health.getDetails().size(), equalTo(0));
}
@Test
public void createWithDetails() throws Exception {
Health health = new Health(Status.UP, Collections.singletonMap("a", "b"));
assertThat(health.getStatus(), equalTo(Status.UP));
assertThat(health.getDetails().get("a"), equalTo((Object) "b"));
}
@Test
public void equalsAndHashCode() throws Exception {
Health h1 = new Health(Status.UP, Collections.singletonMap("a", "b"));
Health h2 = new Health(Status.UP, Collections.singletonMap("a", "b"));
Health h3 = new Health(Status.UP, null);
assertThat(h1, equalTo(h1));
assertThat(h1, equalTo(h2));
assertThat(h1, not(equalTo(h3)));
assertThat(h1.hashCode(), equalTo(h1.hashCode()));
assertThat(h1.hashCode(), equalTo(h2.hashCode()));
assertThat(h1.hashCode(), not(equalTo(h3.hashCode())));
}
@Test
public void withException() throws Exception {
RuntimeException ex = new RuntimeException("bang");
Health health = new Health(Status.UP, Collections.singletonMap("a", "b"))
.withException(ex);
assertThat(health.getDetails().get("a"), equalTo((Object) "b"));
assertThat(health.getDetails().get("error"),
equalTo((Object) "java.lang.RuntimeException: bang"));
}
@Test
public void withDetails() throws Exception {
Health health = new Health(Status.UP, Collections.singletonMap("a", "b"))
.withDetail("c", "d");
assertThat(health.getDetails().get("a"), equalTo((Object) "b"));
assertThat(health.getDetails().get("c"), equalTo((Object) "d"));
}
@Test
public void unknownWithDetails() throws Exception {
Health health = Health.unknown().withDetail("a", "b");
assertThat(health.getStatus(), equalTo(Status.UNKNOWN));
assertThat(health.getDetails().get("a"), equalTo((Object) "b"));
}
@Test
public void unknown() throws Exception {
Health health = Health.unknown();
assertThat(health.getStatus(), equalTo(Status.UNKNOWN));
assertThat(health.getDetails().size(), equalTo(0));
}
@Test
public void upWithDetails() throws Exception {
Health health = Health.up().withDetail("a", "b");
assertThat(health.getStatus(), equalTo(Status.UP));
assertThat(health.getDetails().get("a"), equalTo((Object) "b"));
}
@Test
public void up() throws Exception {
Health health = Health.up();
assertThat(health.getStatus(), equalTo(Status.UP));
assertThat(health.getDetails().size(), equalTo(0));
}
@Test
public void downWithException() throws Exception {
RuntimeException ex = new RuntimeException("bang");
Health health = Health.down(ex);
assertThat(health.getStatus(), equalTo(Status.DOWN));
assertThat(health.getDetails().get("error"),
equalTo((Object) "java.lang.RuntimeException: bang"));
}
@Test
public void down() throws Exception {
Health health = Health.down();
assertThat(health.getStatus(), equalTo(Status.DOWN));
assertThat(health.getDetails().size(), equalTo(0));
}
@Test
public void outOfService() throws Exception {
Health health = Health.outOfService();
assertThat(health.getStatus(), equalTo(Status.OUT_OF_SERVICE));
assertThat(health.getDetails().size(), equalTo(0));
}
@Test
public void statusCode() throws Exception {
Health health = Health.status("UP");
assertThat(health.getStatus(), equalTo(Status.UP));
assertThat(health.getDetails().size(), equalTo(0));
}
@Test
public void status() throws Exception {
Health health = Health.status(Status.UP);
assertThat(health.getStatus(), equalTo(Status.UP));
assertThat(health.getDetails().size(), equalTo(0));
}
}

@ -42,10 +42,10 @@ public class OrderedHealthAggregatorTests {
@Test @Test
public void defaultOrder() { public void defaultOrder() {
Map<String, Health> healths = new HashMap<String, Health>(); Map<String, Health> healths = new HashMap<String, Health>();
healths.put("h1", new Health(Status.DOWN)); healths.put("h1", Health.status(Status.DOWN));
healths.put("h2", new Health(Status.UP)); healths.put("h2", Health.status(Status.UP));
healths.put("h3", new Health(Status.UNKNOWN)); healths.put("h3", Health.status(Status.UNKNOWN));
healths.put("h4", new Health(Status.OUT_OF_SERVICE)); healths.put("h4", Health.status(Status.OUT_OF_SERVICE));
assertEquals(Status.DOWN, this.healthAggregator.aggregate(healths).getStatus()); assertEquals(Status.DOWN, this.healthAggregator.aggregate(healths).getStatus());
} }
@ -54,21 +54,21 @@ public class OrderedHealthAggregatorTests {
this.healthAggregator.setStatusOrder(Status.UNKNOWN, Status.UP, this.healthAggregator.setStatusOrder(Status.UNKNOWN, Status.UP,
Status.OUT_OF_SERVICE, Status.DOWN); Status.OUT_OF_SERVICE, Status.DOWN);
Map<String, Health> healths = new HashMap<String, Health>(); Map<String, Health> healths = new HashMap<String, Health>();
healths.put("h1", new Health(Status.DOWN)); healths.put("h1", Health.status(Status.DOWN));
healths.put("h2", new Health(Status.UP)); healths.put("h2", Health.status(Status.UP));
healths.put("h3", new Health(Status.UNKNOWN)); healths.put("h3", Health.status(Status.UNKNOWN));
healths.put("h4", new Health(Status.OUT_OF_SERVICE)); healths.put("h4", Health.status(Status.OUT_OF_SERVICE));
assertEquals(Status.UNKNOWN, this.healthAggregator.aggregate(healths).getStatus()); assertEquals(Status.UNKNOWN, this.healthAggregator.aggregate(healths).getStatus());
} }
@Test @Test
public void defaultOrderWithCustomStatus() { public void defaultOrderWithCustomStatus() {
Map<String, Health> healths = new HashMap<String, Health>(); Map<String, Health> healths = new HashMap<String, Health>();
healths.put("h1", new Health(Status.DOWN)); healths.put("h1", Health.status(Status.DOWN));
healths.put("h2", new Health(Status.UP)); healths.put("h2", Health.status(Status.UP));
healths.put("h3", new Health(Status.UNKNOWN)); healths.put("h3", Health.status(Status.UNKNOWN));
healths.put("h4", new Health(Status.OUT_OF_SERVICE)); healths.put("h4", Health.status(Status.OUT_OF_SERVICE));
healths.put("h5", new Health(new Status("CUSTOM"))); healths.put("h5", Health.status(new Status("CUSTOM")));
assertEquals(new Status("CUSTOM"), this.healthAggregator.aggregate(healths) assertEquals(new Status("CUSTOM"), this.healthAggregator.aggregate(healths)
.getStatus()); .getStatus());
} }
@ -78,11 +78,11 @@ public class OrderedHealthAggregatorTests {
this.healthAggregator.setStatusOrder(Arrays.asList("DOWN", "OUT_OF_SERVICE", this.healthAggregator.setStatusOrder(Arrays.asList("DOWN", "OUT_OF_SERVICE",
"UP", "UNKNOWN", "CUSTOM")); "UP", "UNKNOWN", "CUSTOM"));
Map<String, Health> healths = new HashMap<String, Health>(); Map<String, Health> healths = new HashMap<String, Health>();
healths.put("h1", new Health(Status.DOWN)); healths.put("h1", Health.status(Status.DOWN));
healths.put("h2", new Health(Status.UP)); healths.put("h2", Health.status(Status.UP));
healths.put("h3", new Health(Status.UNKNOWN)); healths.put("h3", Health.status(Status.UNKNOWN));
healths.put("h4", new Health(Status.OUT_OF_SERVICE)); healths.put("h4", Health.status(Status.OUT_OF_SERVICE));
healths.put("h5", new Health(new Status("CUSTOM"))); healths.put("h5", Health.status(new Status("CUSTOM")));
assertEquals(Status.DOWN, this.healthAggregator.aggregate(healths).getStatus()); assertEquals(Status.DOWN, this.healthAggregator.aggregate(healths).getStatus());
} }

@ -27,8 +27,10 @@ import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.SingleConnectionDataSource; import org.springframework.jdbc.datasource.SingleConnectionDataSource;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -78,7 +80,7 @@ public class SimpleDataSourceHealthIndicatorTests {
this.indicator.setDataSource(this.dataSource); this.indicator.setDataSource(this.dataSource);
this.indicator.setQuery("SELECT COUNT(*) from BAR"); this.indicator.setQuery("SELECT COUNT(*) from BAR");
Health health = this.indicator.health(); Health health = this.indicator.health();
assertNotNull(health.getDetails().get("database")); assertThat(health.getDetails().get("database"), notNullValue());
assertEquals(Status.DOWN, health.getStatus()); assertEquals(Status.DOWN, health.getStatus());
} }

Loading…
Cancel
Save