mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Merge branch '2.7.x' into main
Closes gh-31927
This commit is contained in:
commit
a82b95c955
@ -43,6 +43,10 @@ class AvailabilityProbesHealthEndpointGroups implements HealthEndpointGroups {
|
||||
|
||||
private final Set<String> names;
|
||||
|
||||
private static final String LIVENESS = "liveness";
|
||||
|
||||
private static final String READINESS = "readiness";
|
||||
|
||||
AvailabilityProbesHealthEndpointGroups(HealthEndpointGroups groups, boolean addAdditionalPaths) {
|
||||
Assert.notNull(groups, "Groups must not be null");
|
||||
this.groups = groups;
|
||||
@ -54,18 +58,32 @@ class AvailabilityProbesHealthEndpointGroups implements HealthEndpointGroups {
|
||||
|
||||
private Map<String, HealthEndpointGroup> createProbeGroups(boolean addAdditionalPaths) {
|
||||
Map<String, HealthEndpointGroup> probeGroups = new LinkedHashMap<>();
|
||||
probeGroups.put("liveness", createProbeGroup(addAdditionalPaths, "/livez", "livenessState"));
|
||||
probeGroups.put("readiness", createProbeGroup(addAdditionalPaths, "/readyz", "readinessState"));
|
||||
probeGroups.put(LIVENESS, getOrCreateProbeGroup(addAdditionalPaths, LIVENESS, "/livez", "livenessState"));
|
||||
probeGroups.put(READINESS, getOrCreateProbeGroup(addAdditionalPaths, READINESS, "/readyz", "readinessState"));
|
||||
return Collections.unmodifiableMap(probeGroups);
|
||||
}
|
||||
|
||||
private AvailabilityProbesHealthEndpointGroup createProbeGroup(boolean addAdditionalPath, String path,
|
||||
private HealthEndpointGroup getOrCreateProbeGroup(boolean addAdditionalPath, String name, String path,
|
||||
String members) {
|
||||
HealthEndpointGroup group = this.groups.get(name);
|
||||
if (group != null) {
|
||||
return determineAdditionalPathForExistingGroup(addAdditionalPath, path, group);
|
||||
}
|
||||
AdditionalHealthEndpointPath additionalPath = (!addAdditionalPath) ? null
|
||||
: AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER, path);
|
||||
return new AvailabilityProbesHealthEndpointGroup(additionalPath, members);
|
||||
}
|
||||
|
||||
private HealthEndpointGroup determineAdditionalPathForExistingGroup(boolean addAdditionalPath, String path,
|
||||
HealthEndpointGroup group) {
|
||||
if (addAdditionalPath && group.getAdditionalPath() == null) {
|
||||
AdditionalHealthEndpointPath additionalPath = AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER,
|
||||
path);
|
||||
return new DelegatingAvailabilityProbesHealthEndpointGroup(group, additionalPath);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HealthEndpointGroup getPrimary() {
|
||||
return this.groups.getPrimary();
|
||||
@ -79,15 +97,14 @@ class AvailabilityProbesHealthEndpointGroups implements HealthEndpointGroups {
|
||||
@Override
|
||||
public HealthEndpointGroup get(String name) {
|
||||
HealthEndpointGroup group = this.groups.get(name);
|
||||
if (group == null) {
|
||||
if (group == null || isProbeGroup(name)) {
|
||||
group = this.probeGroups.get(name);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
static boolean containsAllProbeGroups(HealthEndpointGroups groups) {
|
||||
Set<String> names = groups.getNames();
|
||||
return names.contains("liveness") && names.contains("readiness");
|
||||
private boolean isProbeGroup(String name) {
|
||||
return name.equals(LIVENESS) || name.equals(READINESS);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,9 +41,6 @@ class AvailabilityProbesHealthEndpointGroupsPostProcessor implements HealthEndpo
|
||||
|
||||
@Override
|
||||
public HealthEndpointGroups postProcessHealthEndpointGroups(HealthEndpointGroups groups) {
|
||||
if (AvailabilityProbesHealthEndpointGroups.containsAllProbeGroups(groups)) {
|
||||
return groups;
|
||||
}
|
||||
return new AvailabilityProbesHealthEndpointGroups(groups, this.addAdditionalPaths);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.boot.actuate.autoconfigure.availability;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroup;
|
||||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link HealthEndpointGroup} used to support availability probes that delegates to an
|
||||
* existing group.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class DelegatingAvailabilityProbesHealthEndpointGroup implements HealthEndpointGroup {
|
||||
|
||||
private final HealthEndpointGroup delegate;
|
||||
|
||||
private final AdditionalHealthEndpointPath additionalPath;
|
||||
|
||||
DelegatingAvailabilityProbesHealthEndpointGroup(HealthEndpointGroup delegate,
|
||||
AdditionalHealthEndpointPath additionalPath) {
|
||||
Assert.notNull(delegate, "Delegate must not be null");
|
||||
this.delegate = delegate;
|
||||
this.additionalPath = additionalPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMember(String name) {
|
||||
return this.delegate.isMember(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showComponents(SecurityContext securityContext) {
|
||||
return this.delegate.showComponents(securityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showDetails(SecurityContext securityContext) {
|
||||
return this.delegate.showDetails(securityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatusAggregator getStatusAggregator() {
|
||||
return this.delegate.getStatusAggregator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpCodeStatusMapper getHttpCodeStatusMapper() {
|
||||
return this.delegate.getHttpCodeStatusMapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdditionalHealthEndpointPath getAdditionalPath() {
|
||||
return this.additionalPath;
|
||||
}
|
||||
|
||||
}
|
@ -48,7 +48,8 @@ class AvailabilityProbesHealthEndpointGroupsPostProcessorTests {
|
||||
names.add("readiness");
|
||||
names.add("liveness");
|
||||
given(groups.getNames()).willReturn(names);
|
||||
assertThat(this.postProcessor.postProcessHealthEndpointGroups(groups)).isSameAs(groups);
|
||||
assertThat(this.postProcessor.postProcessHealthEndpointGroups(groups))
|
||||
.isInstanceOf(AvailabilityProbesHealthEndpointGroups.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -83,6 +84,25 @@ class AvailabilityProbesHealthEndpointGroupsPostProcessorTests {
|
||||
assertThat(readiness.getAdditionalPath().toString()).isEqualTo("server:/readyz");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postProcessHealthEndpointGroupsWhenGroupsAlreadyContainedAndAdditionalPathPropertyIsTrue() {
|
||||
HealthEndpointGroups groups = mock(HealthEndpointGroups.class);
|
||||
Set<String> names = new LinkedHashSet<>();
|
||||
names.add("test");
|
||||
names.add("readiness");
|
||||
names.add("liveness");
|
||||
given(groups.getNames()).willReturn(names);
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("management.endpoint.health.probes.add-additional-paths", "true");
|
||||
AvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor(
|
||||
environment);
|
||||
HealthEndpointGroups postProcessed = postProcessor.postProcessHealthEndpointGroups(groups);
|
||||
HealthEndpointGroup liveness = postProcessed.get("liveness");
|
||||
HealthEndpointGroup readiness = postProcessed.get("readiness");
|
||||
assertThat(liveness.getAdditionalPath().toString()).isEqualTo("server:/livez");
|
||||
assertThat(readiness.getAdditionalPath().toString()).isEqualTo("server:/readyz");
|
||||
}
|
||||
|
||||
private HealthEndpointGroups getPostProcessed(String value) {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("management.endpoint.health.probes.add-additional-paths", value);
|
||||
|
@ -16,15 +16,15 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.availability;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroup;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
@ -35,6 +35,7 @@ import static org.mockito.Mockito.mock;
|
||||
* Tests for {@link AvailabilityProbesHealthEndpointGroups}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class AvailabilityProbesHealthEndpointGroupsTests {
|
||||
|
||||
@ -69,10 +70,32 @@ class AvailabilityProbesHealthEndpointGroupsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWhenProbeInDelegateReturnsGroupFromDelegate() {
|
||||
given(this.delegate.get("liveness")).willReturn(this.group);
|
||||
void getWhenProbeInDelegateReturnsOriginalGroup() {
|
||||
HealthEndpointGroup group = mock(HealthEndpointGroup.class);
|
||||
HttpCodeStatusMapper mapper = mock(HttpCodeStatusMapper.class);
|
||||
given(group.getHttpCodeStatusMapper()).willReturn(mapper);
|
||||
given(this.delegate.get("liveness")).willReturn(group);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);
|
||||
assertThat(availabilityProbes.get("liveness")).isEqualTo(this.group);
|
||||
assertThat(availabilityProbes.get("liveness")).isEqualTo(group);
|
||||
assertThat(group.getHttpCodeStatusMapper()).isEqualTo(mapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWhenProbeInDelegateAndExistingAdditionalPathReturnsOriginalGroup() {
|
||||
HealthEndpointGroup group = mock(HealthEndpointGroup.class);
|
||||
given(group.getAdditionalPath()).willReturn(AdditionalHealthEndpointPath.from("server:test"));
|
||||
given(this.delegate.get("liveness")).willReturn(group);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, true);
|
||||
HealthEndpointGroup liveness = availabilityProbes.get("liveness");
|
||||
assertThat(liveness).isEqualTo(group);
|
||||
assertThat(liveness.getAdditionalPath().getValue()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWhenProbeInDelegateAndAdditionalPathReturnsGroupWithAdditionalPath() {
|
||||
given(this.delegate.get("liveness")).willReturn(this.group);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, true);
|
||||
assertThat(availabilityProbes.get("liveness").getAdditionalPath().getValue()).isEqualTo("/livez");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -103,22 +126,4 @@ class AvailabilityProbesHealthEndpointGroupsTests {
|
||||
assertThat(probeGroup.isMember("readinessState")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsAllWhenContainsAllReturnTrue() {
|
||||
given(this.delegate.getNames()).willReturn(new LinkedHashSet<>(Arrays.asList("test", "liveness", "readiness")));
|
||||
assertThat(AvailabilityProbesHealthEndpointGroups.containsAllProbeGroups(this.delegate)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsAllWhenContainsOneReturnFalse() {
|
||||
given(this.delegate.getNames()).willReturn(new LinkedHashSet<>(Arrays.asList("test", "liveness")));
|
||||
assertThat(AvailabilityProbesHealthEndpointGroups.containsAllProbeGroups(this.delegate)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsAllWhenContainsNoneReturnFalse() {
|
||||
given(this.delegate.getNames()).willReturn(new LinkedHashSet<>(Arrays.asList("test", "spring")));
|
||||
assertThat(AvailabilityProbesHealthEndpointGroups.containsAllProbeGroups(this.delegate)).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.boot.actuate.autoconfigure.availability;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroup;
|
||||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link DelegatingAvailabilityProbesHealthEndpointGroup}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class DelegatingAvailabilityProbesHealthEndpointGroupTests {
|
||||
|
||||
private DelegatingAvailabilityProbesHealthEndpointGroup group;
|
||||
|
||||
private HttpCodeStatusMapper mapper;
|
||||
|
||||
private StatusAggregator aggregator;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
HealthEndpointGroup delegate = mock(HealthEndpointGroup.class);
|
||||
this.mapper = mock(HttpCodeStatusMapper.class);
|
||||
this.aggregator = mock(StatusAggregator.class);
|
||||
given(delegate.getHttpCodeStatusMapper()).willReturn(this.mapper);
|
||||
given(delegate.getStatusAggregator()).willReturn(this.aggregator);
|
||||
given(delegate.showComponents(any())).willReturn(true);
|
||||
given(delegate.showDetails(any())).willReturn(false);
|
||||
given(delegate.isMember("test")).willReturn(true);
|
||||
this.group = new DelegatingAvailabilityProbesHealthEndpointGroup(delegate,
|
||||
AdditionalHealthEndpointPath.from("server:test"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void groupDelegatesToDelegate() {
|
||||
assertThat(this.group.getHttpCodeStatusMapper()).isEqualTo(this.mapper);
|
||||
assertThat(this.group.getStatusAggregator()).isEqualTo(this.aggregator);
|
||||
assertThat(this.group.isMember("test")).isTrue();
|
||||
assertThat(this.group.showDetails(null)).isFalse();
|
||||
assertThat(this.group.showComponents(null)).isTrue();
|
||||
assertThat(this.group.getAdditionalPath().getValue()).isEqualTo("test");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user