@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2012 - 2018 the original author or authors .
* Copyright 2012 - 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 .
@ -17,13 +17,20 @@
@@ -17,13 +17,20 @@
package org.springframework.boot.actuate.health ;
import java.util.Arrays ;
import java.util.Collections ;
import java.util.HashSet ;
import java.util.Map ;
import java.util.concurrent.Callable ;
import java.util.function.Consumer ;
import org.junit.Test ;
import org.junit.runner.RunWith ;
import reactor.core.publisher.Mono ;
import org.springframework.beans.factory.NoSuchBeanDefinitionException ;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointRunners ;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication ;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type ;
import org.springframework.context.ConfigurableApplicationContext ;
import org.springframework.context.annotation.Bean ;
import org.springframework.context.annotation.Configuration ;
@ -51,23 +58,87 @@ public class HealthEndpointWebIntegrationTests {
@@ -51,23 +58,87 @@ public class HealthEndpointWebIntegrationTests {
}
@Test
public void whenHealthIsDown503ResponseIsReturned ( ) {
public void whenHealthIsDown503ResponseIsReturned ( ) throws Exception {
withHealthIndicator ( "charlie" , ( ) - > Health . down ( ) . build ( ) ,
( ) - > Mono . just ( Health . down ( ) . build ( ) ) , ( ) - > {
client . get ( ) . uri ( "/actuator/health" ) . exchange ( ) . expectStatus ( )
. isEqualTo ( HttpStatus . SERVICE_UNAVAILABLE ) . expectBody ( )
. jsonPath ( "status" ) . isEqualTo ( "DOWN" )
. jsonPath ( "details.alpha.status" ) . isEqualTo ( "UP" )
. jsonPath ( "details.bravo.status" ) . isEqualTo ( "UP" )
. jsonPath ( "details.charlie.status" ) . isEqualTo ( "DOWN" ) ;
return null ;
} ) ;
}
@Test
public void whenComponentHealthIsDown503ResponseIsReturned ( ) throws Exception {
withHealthIndicator ( "charlie" , ( ) - > Health . down ( ) . build ( ) ,
( ) - > Mono . just ( Health . down ( ) . build ( ) ) , ( ) - > {
client . get ( ) . uri ( "/actuator/health/charlie" ) . exchange ( ) . expectStatus ( )
. isEqualTo ( HttpStatus . SERVICE_UNAVAILABLE ) . expectBody ( )
. jsonPath ( "status" ) . isEqualTo ( "DOWN" ) ;
return null ;
} ) ;
}
@Test
public void whenComponentInstanceHealthIsDown503ResponseIsReturned ( )
throws Exception {
CompositeHealthIndicator composite = new CompositeHealthIndicator (
new OrderedHealthAggregator ( ) ,
Collections . singletonMap ( "one" , ( ) - > Health . down ( ) . build ( ) ) ) ;
CompositeReactiveHealthIndicator reactiveComposite = new CompositeReactiveHealthIndicator (
new OrderedHealthAggregator ( ) ,
new DefaultReactiveHealthIndicatorRegistry ( Collections . singletonMap ( "one" ,
( ) - > Mono . just ( Health . down ( ) . build ( ) ) ) ) ) ;
withHealthIndicator ( "charlie" , composite , reactiveComposite , ( ) - > {
client . get ( ) . uri ( "/actuator/health/charlie/one" ) . exchange ( ) . expectStatus ( )
. isEqualTo ( HttpStatus . SERVICE_UNAVAILABLE ) . expectBody ( )
. jsonPath ( "status" ) . isEqualTo ( "DOWN" ) ;
return null ;
} ) ;
}
private void withHealthIndicator ( String name , HealthIndicator healthIndicator ,
ReactiveHealthIndicator reactiveHealthIndicator , Callable < Void > action )
throws Exception {
Consumer < String > unregister ;
Consumer < String > reactiveUnregister ;
try {
ReactiveHealthIndicatorRegistry registry = context
. getBean ( ReactiveHealthIndicatorRegistry . class ) ;
registry . register ( name , reactiveHealthIndicator ) ;
reactiveUnregister = registry : : unregister ;
}
catch ( NoSuchBeanDefinitionException ex ) {
reactiveUnregister = ( indicatorName ) - > {
} ;
// Continue
}
HealthIndicatorRegistry registry = context . getBean ( HealthIndicatorRegistry . class ) ;
registry . register ( "charlie" , ( ) - > Health . down ( ) . build ( ) ) ;
registry . register ( name , healthIndicator ) ;
unregister = reactiveUnregister . andThen ( registry : : unregister ) ;
try {
client . get ( ) . uri ( "/actuator/health" ) . exchange ( ) . expectStatus ( )
. isEqualTo ( HttpStatus . SERVICE_UNAVAILABLE ) . expectBody ( )
. jsonPath ( "status" ) . isEqualTo ( "DOWN" ) . jsonPath ( "details.alpha.status" )
. isEqualTo ( "UP" ) . jsonPath ( "details.bravo.status" ) . isEqualTo ( "UP" )
. jsonPath ( "details.charlie.status" ) . isEqualTo ( "DOWN" ) ;
action . call ( ) ;
}
finally {
registry . unregister ( "charlie" ) ;
unregister . accept ( "charlie" ) ;
}
}
@Test
public void whenHealthIndicatorIsRemovedResponseIsAltered ( ) {
Consumer < String > reactiveRegister = null ;
try {
ReactiveHealthIndicatorRegistry registry = context
. getBean ( ReactiveHealthIndicatorRegistry . class ) ;
ReactiveHealthIndicator unregistered = registry . unregister ( "bravo" ) ;
reactiveRegister = ( name ) - > registry . register ( name , unregistered ) ;
}
catch ( NoSuchBeanDefinitionException ex ) {
// Continue
}
HealthIndicatorRegistry registry = context . getBean ( HealthIndicatorRegistry . class ) ;
HealthIndicator bravo = registry . unregister ( "bravo" ) ;
try {
@ -78,6 +149,9 @@ public class HealthEndpointWebIntegrationTests {
@@ -78,6 +149,9 @@ public class HealthEndpointWebIntegrationTests {
}
finally {
registry . register ( "bravo" , bravo ) ;
if ( reactiveRegister ! = null ) {
reactiveRegister . accept ( "bravo" ) ;
}
}
}
@ -91,6 +165,16 @@ public class HealthEndpointWebIntegrationTests {
@@ -91,6 +165,16 @@ public class HealthEndpointWebIntegrationTests {
. createHealthIndicatorRegistry ( healthIndicators ) ;
}
@Bean
@ConditionalOnWebApplication ( type = Type . REACTIVE )
public ReactiveHealthIndicatorRegistry reactiveHealthIndicatorRegistry (
Map < String , ReactiveHealthIndicator > reactiveHealthIndicators ,
Map < String , HealthIndicator > healthIndicators ) {
return new ReactiveHealthIndicatorRegistryFactory ( )
. createReactiveHealthIndicatorRegistry ( reactiveHealthIndicators ,
healthIndicators ) ;
}
@Bean
public HealthEndpoint healthEndpoint ( HealthIndicatorRegistry registry ) {
return new HealthEndpoint ( new CompositeHealthIndicator (
@ -98,6 +182,7 @@ public class HealthEndpointWebIntegrationTests {
@@ -98,6 +182,7 @@ public class HealthEndpointWebIntegrationTests {
}
@Bean
@ConditionalOnWebApplication ( type = Type . SERVLET )
public HealthEndpointWebExtension healthWebEndpointExtension (
HealthEndpoint healthEndpoint ) {
return new HealthEndpointWebExtension ( healthEndpoint ,
@ -106,6 +191,18 @@ public class HealthEndpointWebIntegrationTests {
@@ -106,6 +191,18 @@ public class HealthEndpointWebIntegrationTests {
new HashSet < > ( Arrays . asList ( "ACTUATOR" ) ) ) ) ;
}
@Bean
@ConditionalOnWebApplication ( type = Type . REACTIVE )
public ReactiveHealthEndpointWebExtension reactiveHealthWebEndpointExtension (
ReactiveHealthIndicatorRegistry registry , HealthEndpoint healthEndpoint ) {
return new ReactiveHealthEndpointWebExtension (
new CompositeReactiveHealthIndicator ( new OrderedHealthAggregator ( ) ,
registry ) ,
new HealthWebEndpointResponseMapper ( new HealthStatusHttpMapper ( ) ,
ShowDetails . ALWAYS ,
new HashSet < > ( Arrays . asList ( "ACTUATOR" ) ) ) ) ;
}
@Bean
public HealthIndicator alphaHealthIndicator ( ) {
return ( ) - > Health . up ( ) . build ( ) ;