Skip to content

Commit 86a1c96

Browse files
committed
Make sure health endpoint is available with no contributor
This commit makes sure that the health endpoint returns a default health status when no contributors are available. Previously, it was returning `null` which leads to a 404 when exposed via HTTP. Closes gh-18676
1 parent f57baa7 commit 86a1c96

File tree

7 files changed

+48
-3
lines changed

7 files changed

+48
-3
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ public HealthEndpoint(HealthContributorRegistry registry, HealthEndpointGroups g
6262

6363
@ReadOperation
6464
public HealthComponent health() {
65-
return health(ApiVersion.V3, EMPTY_PATH);
65+
HealthComponent health = health(ApiVersion.V3, EMPTY_PATH);
66+
return (health != null) ? health : DEFAULT_HEALTH;
6667
}
6768

6869
@ReadOperation

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointSupport.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
*/
3535
abstract class HealthEndpointSupport<C, T> {
3636

37+
static final Health DEFAULT_HEALTH = Health.up().build();
38+
3739
private final ContributorRegistry<C> registry;
3840

3941
private final HealthEndpointGroups groups;

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.actuate.health;
1818

19+
import java.util.Arrays;
1920
import java.util.Map;
2021
import java.util.Set;
2122

@@ -79,7 +80,9 @@ public WebEndpointResponse<HealthComponent> health(ApiVersion apiVersion, Securi
7980
boolean showAll, String... path) {
8081
HealthResult<HealthComponent> result = getHealth(apiVersion, securityContext, showAll, path);
8182
if (result == null) {
82-
return new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND);
83+
return (Arrays.equals(path, NO_PATH))
84+
? new WebEndpointResponse<>(DEFAULT_HEALTH, WebEndpointResponse.STATUS_OK)
85+
: new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND);
8386
}
8487
HealthComponent health = result.getHealth();
8588
HealthEndpointGroup group = result.getGroup();

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthEndpointWebExtension.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.actuate.health;
1818

19+
import java.util.Arrays;
1920
import java.util.Map;
2021
import java.util.Set;
2122

@@ -81,7 +82,9 @@ public Mono<WebEndpointResponse<? extends HealthComponent>> health(ApiVersion ap
8182
SecurityContext securityContext, boolean showAll, String... path) {
8283
HealthResult<Mono<? extends HealthComponent>> result = getHealth(apiVersion, securityContext, showAll, path);
8384
if (result == null) {
84-
return Mono.just(new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND));
85+
return (Arrays.equals(path, NO_PATH))
86+
? Mono.just(new WebEndpointResponse<>(DEFAULT_HEALTH, WebEndpointResponse.STATUS_OK))
87+
: Mono.just(new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND));
8588
}
8689
HealthEndpointGroup group = result.getGroup();
8790
return result.getHealth().map((health) -> {

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.actuate.health;
1818

19+
import java.util.Collections;
1920
import java.util.Map;
2021

2122
import org.junit.jupiter.api.Test;
@@ -51,6 +52,15 @@ void healthReturnsSystemHealth() {
5152
assertThat(health).isInstanceOf(SystemHealth.class);
5253
}
5354

55+
@Test
56+
void healthWithNoContributorReturnsUp() {
57+
assertThat(this.registry).isEmpty();
58+
HealthComponent health = create(this.registry,
59+
HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap())).health();
60+
assertThat(health.getStatus()).isEqualTo(Status.UP);
61+
assertThat(health).isInstanceOf(Health.class);
62+
}
63+
5464
@Test
5565
void healthWhenPathDoesNotExistReturnsNull() {
5666
this.registry.registerContributor("test", createContributor(this.up));

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebExtensionTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.actuate.health;
1818

19+
import java.util.Collections;
1920
import java.util.Map;
2021

2122
import org.junit.jupiter.api.Test;
@@ -58,6 +59,18 @@ void healthReturnsSystemHealth() {
5859
assertThat(response.getStatus()).isEqualTo(200);
5960
}
6061

62+
@Test
63+
void healthWithNoContributorReturnsUp() {
64+
assertThat(this.registry).isEmpty();
65+
WebEndpointResponse<HealthComponent> response = create(this.registry,
66+
HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap()))
67+
.health(ApiVersion.LATEST, SecurityContext.NONE);
68+
assertThat(response.getStatus()).isEqualTo(200);
69+
HealthComponent health = response.getBody();
70+
assertThat(health.getStatus()).isEqualTo(Status.UP);
71+
assertThat(health).isInstanceOf(Health.class);
72+
}
73+
6174
@Test
6275
void healthWhenPathDoesNotExistReturnsHttp404() {
6376
this.registry.registerContributor("test", createContributor(this.up));

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthEndpointWebExtensionTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.actuate.health;
1818

19+
import java.util.Collections;
1920
import java.util.Map;
2021

2122
import org.junit.jupiter.api.Test;
@@ -60,6 +61,18 @@ void healthReturnsSystemHealth() {
6061
assertThat(response.getStatus()).isEqualTo(200);
6162
}
6263

64+
@Test
65+
void healthWithNoContributorReturnsUp() {
66+
assertThat(this.registry).isEmpty();
67+
WebEndpointResponse<? extends HealthComponent> response = create(this.registry,
68+
HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap()))
69+
.health(ApiVersion.LATEST, SecurityContext.NONE).block();
70+
assertThat(response.getStatus()).isEqualTo(200);
71+
HealthComponent health = response.getBody();
72+
assertThat(health.getStatus()).isEqualTo(Status.UP);
73+
assertThat(health).isInstanceOf(Health.class);
74+
}
75+
6376
@Test
6477
void healthWhenPathDoesNotExistReturnsHttp404() {
6578
this.registry.registerContributor("test", createContributor(this.up));

0 commit comments

Comments
 (0)