Skip to content

Commit 2884ec8

Browse files
committed
Merge branch '2.6.x' into 2.7.x
Closes gh-31926
2 parents 4806881 + cc15eb0 commit 2884ec8

File tree

6 files changed

+217
-34
lines changed

6 files changed

+217
-34
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesHealthEndpointGroups.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class AvailabilityProbesHealthEndpointGroups implements HealthEndpointGroups {
4343

4444
private final Set<String> names;
4545

46+
private static final String LIVENESS = "liveness";
47+
48+
private static final String READINESS = "readiness";
49+
4650
AvailabilityProbesHealthEndpointGroups(HealthEndpointGroups groups, boolean addAdditionalPaths) {
4751
Assert.notNull(groups, "Groups must not be null");
4852
this.groups = groups;
@@ -54,18 +58,32 @@ class AvailabilityProbesHealthEndpointGroups implements HealthEndpointGroups {
5458

5559
private Map<String, HealthEndpointGroup> createProbeGroups(boolean addAdditionalPaths) {
5660
Map<String, HealthEndpointGroup> probeGroups = new LinkedHashMap<>();
57-
probeGroups.put("liveness", createProbeGroup(addAdditionalPaths, "/livez", "livenessState"));
58-
probeGroups.put("readiness", createProbeGroup(addAdditionalPaths, "/readyz", "readinessState"));
61+
probeGroups.put(LIVENESS, getOrCreateProbeGroup(addAdditionalPaths, LIVENESS, "/livez", "livenessState"));
62+
probeGroups.put(READINESS, getOrCreateProbeGroup(addAdditionalPaths, READINESS, "/readyz", "readinessState"));
5963
return Collections.unmodifiableMap(probeGroups);
6064
}
6165

62-
private AvailabilityProbesHealthEndpointGroup createProbeGroup(boolean addAdditionalPath, String path,
66+
private HealthEndpointGroup getOrCreateProbeGroup(boolean addAdditionalPath, String name, String path,
6367
String members) {
68+
HealthEndpointGroup group = this.groups.get(name);
69+
if (group != null) {
70+
return determineAdditionalPathForExistingGroup(addAdditionalPath, path, group);
71+
}
6472
AdditionalHealthEndpointPath additionalPath = (!addAdditionalPath) ? null
6573
: AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER, path);
6674
return new AvailabilityProbesHealthEndpointGroup(additionalPath, members);
6775
}
6876

77+
private HealthEndpointGroup determineAdditionalPathForExistingGroup(boolean addAdditionalPath, String path,
78+
HealthEndpointGroup group) {
79+
if (addAdditionalPath && group.getAdditionalPath() == null) {
80+
AdditionalHealthEndpointPath additionalPath = AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER,
81+
path);
82+
return new DelegatingAvailabilityProbesHealthEndpointGroup(group, additionalPath);
83+
}
84+
return group;
85+
}
86+
6987
@Override
7088
public HealthEndpointGroup getPrimary() {
7189
return this.groups.getPrimary();
@@ -79,15 +97,14 @@ public Set<String> getNames() {
7997
@Override
8098
public HealthEndpointGroup get(String name) {
8199
HealthEndpointGroup group = this.groups.get(name);
82-
if (group == null) {
100+
if (group == null || isProbeGroup(name)) {
83101
group = this.probeGroups.get(name);
84102
}
85103
return group;
86104
}
87105

88-
static boolean containsAllProbeGroups(HealthEndpointGroups groups) {
89-
Set<String> names = groups.getNames();
90-
return names.contains("liveness") && names.contains("readiness");
106+
private boolean isProbeGroup(String name) {
107+
return name.equals(LIVENESS) || name.equals(READINESS);
91108
}
92109

93110
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesHealthEndpointGroupsPostProcessor.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ class AvailabilityProbesHealthEndpointGroupsPostProcessor implements HealthEndpo
4141

4242
@Override
4343
public HealthEndpointGroups postProcessHealthEndpointGroups(HealthEndpointGroups groups) {
44-
if (AvailabilityProbesHealthEndpointGroups.containsAllProbeGroups(groups)) {
45-
return groups;
46-
}
4744
return new AvailabilityProbesHealthEndpointGroups(groups, this.addAdditionalPaths);
4845
}
4946

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.availability;
18+
19+
import org.springframework.boot.actuate.endpoint.SecurityContext;
20+
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
21+
import org.springframework.boot.actuate.health.HealthEndpointGroup;
22+
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
23+
import org.springframework.boot.actuate.health.StatusAggregator;
24+
import org.springframework.util.Assert;
25+
26+
/**
27+
* {@link HealthEndpointGroup} used to support availability probes that delegates to an
28+
* existing group.
29+
*
30+
* @author Madhura Bhave
31+
*/
32+
class DelegatingAvailabilityProbesHealthEndpointGroup implements HealthEndpointGroup {
33+
34+
private final HealthEndpointGroup delegate;
35+
36+
private final AdditionalHealthEndpointPath additionalPath;
37+
38+
DelegatingAvailabilityProbesHealthEndpointGroup(HealthEndpointGroup delegate,
39+
AdditionalHealthEndpointPath additionalPath) {
40+
Assert.notNull(delegate, "Delegate must not be null");
41+
this.delegate = delegate;
42+
this.additionalPath = additionalPath;
43+
}
44+
45+
@Override
46+
public boolean isMember(String name) {
47+
return this.delegate.isMember(name);
48+
}
49+
50+
@Override
51+
public boolean showComponents(SecurityContext securityContext) {
52+
return this.delegate.showComponents(securityContext);
53+
}
54+
55+
@Override
56+
public boolean showDetails(SecurityContext securityContext) {
57+
return this.delegate.showDetails(securityContext);
58+
}
59+
60+
@Override
61+
public StatusAggregator getStatusAggregator() {
62+
return this.delegate.getStatusAggregator();
63+
}
64+
65+
@Override
66+
public HttpCodeStatusMapper getHttpCodeStatusMapper() {
67+
return this.delegate.getHttpCodeStatusMapper();
68+
}
69+
70+
@Override
71+
public AdditionalHealthEndpointPath getAdditionalPath() {
72+
return this.additionalPath;
73+
}
74+
75+
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesHealthEndpointGroupsPostProcessorTests.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ void postProcessHealthEndpointGroupsWhenGroupsAlreadyContainedReturnsOriginal()
4848
names.add("readiness");
4949
names.add("liveness");
5050
given(groups.getNames()).willReturn(names);
51-
assertThat(this.postProcessor.postProcessHealthEndpointGroups(groups)).isSameAs(groups);
51+
assertThat(this.postProcessor.postProcessHealthEndpointGroups(groups))
52+
.isInstanceOf(AvailabilityProbesHealthEndpointGroups.class);
5253
}
5354

5455
@Test
@@ -83,6 +84,25 @@ void postProcessHealthEndpointGroupsWhenAdditionalPathPropertyIsTrue() {
8384
assertThat(readiness.getAdditionalPath().toString()).isEqualTo("server:/readyz");
8485
}
8586

87+
@Test
88+
void postProcessHealthEndpointGroupsWhenGroupsAlreadyContainedAndAdditionalPathPropertyIsTrue() {
89+
HealthEndpointGroups groups = mock(HealthEndpointGroups.class);
90+
Set<String> names = new LinkedHashSet<>();
91+
names.add("test");
92+
names.add("readiness");
93+
names.add("liveness");
94+
given(groups.getNames()).willReturn(names);
95+
MockEnvironment environment = new MockEnvironment();
96+
environment.setProperty("management.endpoint.health.probes.add-additional-paths", "true");
97+
AvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor(
98+
environment);
99+
HealthEndpointGroups postProcessed = postProcessor.postProcessHealthEndpointGroups(groups);
100+
HealthEndpointGroup liveness = postProcessed.get("liveness");
101+
HealthEndpointGroup readiness = postProcessed.get("readiness");
102+
assertThat(liveness.getAdditionalPath().toString()).isEqualTo("server:/livez");
103+
assertThat(readiness.getAdditionalPath().toString()).isEqualTo("server:/readyz");
104+
}
105+
86106
private HealthEndpointGroups getPostProcessed(String value) {
87107
MockEnvironment environment = new MockEnvironment();
88108
environment.setProperty("management.endpoint.health.probes.add-additional-paths", value);

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesHealthEndpointGroupsTests.java

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.availability;
1818

19-
import java.util.Arrays;
2019
import java.util.Collections;
21-
import java.util.LinkedHashSet;
2220

2321
import org.junit.jupiter.api.BeforeEach;
2422
import org.junit.jupiter.api.Test;
2523

24+
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
2625
import org.springframework.boot.actuate.health.HealthEndpointGroup;
2726
import org.springframework.boot.actuate.health.HealthEndpointGroups;
27+
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
2828

2929
import static org.assertj.core.api.Assertions.assertThat;
3030
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@@ -35,6 +35,7 @@
3535
* Tests for {@link AvailabilityProbesHealthEndpointGroups}.
3636
*
3737
* @author Phillip Webb
38+
* @author Madhura Bhave
3839
*/
3940
class AvailabilityProbesHealthEndpointGroupsTests {
4041

@@ -69,10 +70,32 @@ void getNamesIncludesAvailabilityProbeGroups() {
6970
}
7071

7172
@Test
72-
void getWhenProbeInDelegateReturnsGroupFromDelegate() {
73-
given(this.delegate.get("liveness")).willReturn(this.group);
73+
void getWhenProbeInDelegateReturnsOriginalGroup() {
74+
HealthEndpointGroup group = mock(HealthEndpointGroup.class);
75+
HttpCodeStatusMapper mapper = mock(HttpCodeStatusMapper.class);
76+
given(group.getHttpCodeStatusMapper()).willReturn(mapper);
77+
given(this.delegate.get("liveness")).willReturn(group);
7478
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);
75-
assertThat(availabilityProbes.get("liveness")).isEqualTo(this.group);
79+
assertThat(availabilityProbes.get("liveness")).isEqualTo(group);
80+
assertThat(group.getHttpCodeStatusMapper()).isEqualTo(mapper);
81+
}
82+
83+
@Test
84+
void getWhenProbeInDelegateAndExistingAdditionalPathReturnsOriginalGroup() {
85+
HealthEndpointGroup group = mock(HealthEndpointGroup.class);
86+
given(group.getAdditionalPath()).willReturn(AdditionalHealthEndpointPath.from("server:test"));
87+
given(this.delegate.get("liveness")).willReturn(group);
88+
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, true);
89+
HealthEndpointGroup liveness = availabilityProbes.get("liveness");
90+
assertThat(liveness).isEqualTo(group);
91+
assertThat(liveness.getAdditionalPath().getValue()).isEqualTo("test");
92+
}
93+
94+
@Test
95+
void getWhenProbeInDelegateAndAdditionalPathReturnsGroupWithAdditionalPath() {
96+
given(this.delegate.get("liveness")).willReturn(this.group);
97+
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, true);
98+
assertThat(availabilityProbes.get("liveness").getAdditionalPath().getValue()).isEqualTo("/livez");
7699
}
77100

78101
@Test
@@ -103,22 +126,4 @@ void getReadinessProbeHasOnlyReadinessStateAsMember() {
103126
assertThat(probeGroup.isMember("readinessState")).isTrue();
104127
}
105128

106-
@Test
107-
void containsAllWhenContainsAllReturnTrue() {
108-
given(this.delegate.getNames()).willReturn(new LinkedHashSet<>(Arrays.asList("test", "liveness", "readiness")));
109-
assertThat(AvailabilityProbesHealthEndpointGroups.containsAllProbeGroups(this.delegate)).isTrue();
110-
}
111-
112-
@Test
113-
void containsAllWhenContainsOneReturnFalse() {
114-
given(this.delegate.getNames()).willReturn(new LinkedHashSet<>(Arrays.asList("test", "liveness")));
115-
assertThat(AvailabilityProbesHealthEndpointGroups.containsAllProbeGroups(this.delegate)).isFalse();
116-
}
117-
118-
@Test
119-
void containsAllWhenContainsNoneReturnFalse() {
120-
given(this.delegate.getNames()).willReturn(new LinkedHashSet<>(Arrays.asList("test", "spring")));
121-
assertThat(AvailabilityProbesHealthEndpointGroups.containsAllProbeGroups(this.delegate)).isFalse();
122-
}
123-
124129
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2012-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.availability;
18+
19+
import org.junit.jupiter.api.BeforeEach;
20+
import org.junit.jupiter.api.Test;
21+
22+
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
23+
import org.springframework.boot.actuate.health.HealthEndpointGroup;
24+
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
25+
import org.springframework.boot.actuate.health.StatusAggregator;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
import static org.mockito.ArgumentMatchers.any;
29+
import static org.mockito.BDDMockito.given;
30+
import static org.mockito.Mockito.mock;
31+
32+
/**
33+
* Tests for {@link DelegatingAvailabilityProbesHealthEndpointGroup}.
34+
*
35+
* @author Madhura Bhave
36+
*/
37+
class DelegatingAvailabilityProbesHealthEndpointGroupTests {
38+
39+
private DelegatingAvailabilityProbesHealthEndpointGroup group;
40+
41+
private HttpCodeStatusMapper mapper;
42+
43+
private StatusAggregator aggregator;
44+
45+
@BeforeEach
46+
void setup() {
47+
HealthEndpointGroup delegate = mock(HealthEndpointGroup.class);
48+
this.mapper = mock(HttpCodeStatusMapper.class);
49+
this.aggregator = mock(StatusAggregator.class);
50+
given(delegate.getHttpCodeStatusMapper()).willReturn(this.mapper);
51+
given(delegate.getStatusAggregator()).willReturn(this.aggregator);
52+
given(delegate.showComponents(any())).willReturn(true);
53+
given(delegate.showDetails(any())).willReturn(false);
54+
given(delegate.isMember("test")).willReturn(true);
55+
this.group = new DelegatingAvailabilityProbesHealthEndpointGroup(delegate,
56+
AdditionalHealthEndpointPath.from("server:test"));
57+
}
58+
59+
@Test
60+
void groupDelegatesToDelegate() {
61+
assertThat(this.group.getHttpCodeStatusMapper()).isEqualTo(this.mapper);
62+
assertThat(this.group.getStatusAggregator()).isEqualTo(this.aggregator);
63+
assertThat(this.group.isMember("test")).isTrue();
64+
assertThat(this.group.showDetails(null)).isFalse();
65+
assertThat(this.group.showComponents(null)).isTrue();
66+
assertThat(this.group.getAdditionalPath().getValue()).isEqualTo("test");
67+
}
68+
69+
}

0 commit comments

Comments
 (0)