Filter properties with a particular prefix
This commit improves the configprops endpoint to allow filtering properties based on a particular prefix See gh-24718
This commit is contained in:
parent
0f9fb13141
commit
ad7c69a9cd
|
@ -6,15 +6,15 @@ The `configprops` endpoint provides information about the application's `@Config
|
||||||
|
|
||||||
|
|
||||||
[[configprops-retrieving]]
|
[[configprops-retrieving]]
|
||||||
== Retrieving the @ConfigurationProperties Bean
|
== Retrieving All @ConfigurationProperties Beans
|
||||||
|
|
||||||
To retrieve the `@ConfigurationProperties` beans, make a `GET` request to `/actuator/configprops`, as shown in the following curl-based example:
|
To retrieve all of the `@ConfigurationProperties` beans, make a `GET` request to `/actuator/configprops`, as shown in the following curl-based example:
|
||||||
|
|
||||||
include::{snippets}/configprops/curl-request.adoc[]
|
include::{snippets}/configprops/all/curl-request.adoc[]
|
||||||
|
|
||||||
The resulting response is similar to the following:
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
include::{snippets}/configprops/http-response.adoc[]
|
include::{snippets}/configprops/all/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,3 +26,26 @@ The following table describes the structure of the response:
|
||||||
|
|
||||||
[cols="2,1,3"]
|
[cols="2,1,3"]
|
||||||
include::{snippets}/configprops/response-fields.adoc[]
|
include::{snippets}/configprops/response-fields.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
[[configprops-retrieving-by-prefix]]
|
||||||
|
== Retrieving @ConfigurationProperties Beans By Prefix
|
||||||
|
|
||||||
|
To retrieve the `@ConfigurationProperties` beans mapped under a certain prefix, make a `GET` request to `/actuator/configprops/{prefix}`, as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}/configprops/prefixed/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}/configprops/prefixed/http-response.adoc[]
|
||||||
|
|
||||||
|
NOTE: The `{prefix}` does not need to be exact, a more general prefix will return all beans mapped under that prefix stem.
|
||||||
|
|
||||||
|
[[configprops-retrieving-by-prefix-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the application's `@ConfigurationProperties` beans.
|
||||||
|
The following table describes the structure of the response:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}/configprops/prefixed/response-fields.adoc[]
|
|
@ -18,7 +18,9 @@ package org.springframework.boot.actuate.autoconfigure.context.properties;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
||||||
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint;
|
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint;
|
||||||
|
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpointWebExtension;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -30,6 +32,7 @@ import org.springframework.context.annotation.Configuration;
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Chris Bono
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ -49,4 +52,12 @@ public class ConfigurationPropertiesReportEndpointAutoConfiguration {
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
@ConditionalOnBean(ConfigurationPropertiesReportEndpoint.class)
|
||||||
|
public ConfigurationPropertiesReportEndpointWebExtension configurationPropertiesReportEndpointWebExtension(
|
||||||
|
ConfigurationPropertiesReportEndpoint configurationPropertiesReportEndpoint) {
|
||||||
|
return new ConfigurationPropertiesReportEndpointWebExtension(configurationPropertiesReportEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,13 +36,31 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
* {@link ConfigurationPropertiesReportEndpoint}.
|
* {@link ConfigurationPropertiesReportEndpoint}.
|
||||||
*
|
*
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
|
* @author Chris Bono
|
||||||
*/
|
*/
|
||||||
class ConfigurationPropertiesReportEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
class ConfigurationPropertiesReportEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void configProps() throws Exception {
|
void configProps() throws Exception {
|
||||||
this.mockMvc.perform(get("/actuator/configprops")).andExpect(status().isOk())
|
this.mockMvc.perform(get("/actuator/configprops")).andExpect(status().isOk())
|
||||||
.andDo(MockMvcRestDocumentation.document("configprops",
|
.andDo(MockMvcRestDocumentation.document("configprops/all",
|
||||||
|
preprocessResponse(limit("contexts", getApplicationContext().getId(), "beans")),
|
||||||
|
responseFields(fieldWithPath("contexts").description("Application contexts keyed by id."),
|
||||||
|
fieldWithPath("contexts.*.beans.*")
|
||||||
|
.description("`@ConfigurationProperties` beans keyed by bean name."),
|
||||||
|
fieldWithPath("contexts.*.beans.*.prefix")
|
||||||
|
.description("Prefix applied to the names of the bean's properties."),
|
||||||
|
subsectionWithPath("contexts.*.beans.*.properties")
|
||||||
|
.description("Properties of the bean as name-value pairs."),
|
||||||
|
subsectionWithPath("contexts.*.beans.*.inputs").description(
|
||||||
|
"Origin and value of the configuration property used when binding to this bean."),
|
||||||
|
parentIdField())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void configPropsFilterByPrefix() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/actuator/configprops/spring.resources")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("configprops/prefixed",
|
||||||
preprocessResponse(limit("contexts", getApplicationContext().getId(), "beans")),
|
preprocessResponse(limit("contexts", getApplicationContext().getId(), "beans")),
|
||||||
responseFields(fieldWithPath("contexts").description("Application contexts keyed by id."),
|
responseFields(fieldWithPath("contexts").description("Application contexts keyed by id."),
|
||||||
fieldWithPath("contexts.*.beans.*")
|
fieldWithPath("contexts.*.beans.*")
|
||||||
|
|
|
@ -26,6 +26,7 @@ import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||||
|
@ -55,6 +56,7 @@ import org.springframework.beans.BeansException;
|
||||||
import org.springframework.boot.actuate.endpoint.Sanitizer;
|
import org.springframework.boot.actuate.endpoint.Sanitizer;
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||||
|
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||||
import org.springframework.boot.context.properties.BoundConfigurationProperties;
|
import org.springframework.boot.context.properties.BoundConfigurationProperties;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBean;
|
import org.springframework.boot.context.properties.ConfigurationPropertiesBean;
|
||||||
|
@ -90,6 +92,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
|
* @author Chris Bono
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@Endpoint(id = "configprops")
|
@Endpoint(id = "configprops")
|
||||||
|
@ -114,15 +117,21 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
||||||
|
|
||||||
@ReadOperation
|
@ReadOperation
|
||||||
public ApplicationConfigurationProperties configurationProperties() {
|
public ApplicationConfigurationProperties configurationProperties() {
|
||||||
return extract(this.context);
|
return extract(this.context, (bean) -> true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApplicationConfigurationProperties extract(ApplicationContext context) {
|
@ReadOperation
|
||||||
|
public ApplicationConfigurationProperties configurationProperties(@Selector String prefix) {
|
||||||
|
return extract(this.context, (bean) -> bean.getAnnotation().prefix().startsWith(prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApplicationConfigurationProperties extract(ApplicationContext context,
|
||||||
|
Predicate<ConfigurationPropertiesBean> beanFilterPredicate) {
|
||||||
ObjectMapper mapper = getObjectMapper();
|
ObjectMapper mapper = getObjectMapper();
|
||||||
Map<String, ContextConfigurationProperties> contexts = new HashMap<>();
|
Map<String, ContextConfigurationProperties> contexts = new HashMap<>();
|
||||||
ApplicationContext target = context;
|
ApplicationContext target = context;
|
||||||
while (target != null) {
|
while (target != null) {
|
||||||
contexts.put(target.getId(), describeBeans(mapper, target));
|
contexts.put(target.getId(), describeBeans(mapper, target, beanFilterPredicate));
|
||||||
target = target.getParent();
|
target = target.getParent();
|
||||||
}
|
}
|
||||||
return new ApplicationConfigurationProperties(contexts);
|
return new ApplicationConfigurationProperties(contexts);
|
||||||
|
@ -169,10 +178,14 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
||||||
mapper.setSerializerFactory(factory);
|
mapper.setSerializerFactory(factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContextConfigurationProperties describeBeans(ObjectMapper mapper, ApplicationContext context) {
|
private ContextConfigurationProperties describeBeans(ObjectMapper mapper, ApplicationContext context,
|
||||||
|
Predicate<ConfigurationPropertiesBean> beanFilterPredicate) {
|
||||||
Map<String, ConfigurationPropertiesBean> beans = ConfigurationPropertiesBean.getAll(context);
|
Map<String, ConfigurationPropertiesBean> beans = ConfigurationPropertiesBean.getAll(context);
|
||||||
Map<String, ConfigurationPropertiesBeanDescriptor> descriptors = new HashMap<>();
|
|
||||||
beans.forEach((beanName, bean) -> descriptors.put(beanName, describeBean(mapper, bean)));
|
Map<String, ConfigurationPropertiesBeanDescriptor> descriptors = beans.values().stream()
|
||||||
|
.filter(beanFilterPredicate::test)
|
||||||
|
.collect(Collectors.toMap((bean) -> bean.getName(), (bean) -> describeBean(mapper, bean)));
|
||||||
|
|
||||||
return new ContextConfigurationProperties(descriptors,
|
return new ContextConfigurationProperties(descriptors,
|
||||||
(context.getParent() != null) ? context.getParent().getId() : null);
|
(context.getParent() != null) ? context.getParent().getId() : null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2020 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.context.properties;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ApplicationConfigurationProperties;
|
||||||
|
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ContextConfigurationProperties;
|
||||||
|
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||||
|
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||||
|
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||||
|
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EndpointWebExtension @EndpointWebExtension} for the
|
||||||
|
* {@link ConfigurationPropertiesReportEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Chris Bono
|
||||||
|
* @since 2.4
|
||||||
|
*/
|
||||||
|
@EndpointWebExtension(endpoint = ConfigurationPropertiesReportEndpoint.class)
|
||||||
|
public class ConfigurationPropertiesReportEndpointWebExtension {
|
||||||
|
|
||||||
|
private final ConfigurationPropertiesReportEndpoint delegate;
|
||||||
|
|
||||||
|
public ConfigurationPropertiesReportEndpointWebExtension(ConfigurationPropertiesReportEndpoint delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReadOperation
|
||||||
|
public WebEndpointResponse<ApplicationConfigurationProperties> configurationProperties(@Selector String prefix) {
|
||||||
|
ApplicationConfigurationProperties configurationProperties = this.delegate.configurationProperties(prefix);
|
||||||
|
boolean foundMatchingBeans = configurationProperties.getContexts().values().stream()
|
||||||
|
.map(ContextConfigurationProperties::getBeans).anyMatch((beans) -> !beans.isEmpty());
|
||||||
|
return (foundMatchingBeans) ? new WebEndpointResponse<>(configurationProperties, WebEndpointResponse.STATUS_OK)
|
||||||
|
: new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* 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.context.properties;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ApplicationConfigurationProperties;
|
||||||
|
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ContextConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link ConfigurationPropertiesReportEndpoint} when filtering by prefix.
|
||||||
|
*
|
||||||
|
* @author Chris Bono
|
||||||
|
*/
|
||||||
|
class ConfigurationPropertiesReportEndpointFilteringTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void filterByPrefixSingleMatch() {
|
||||||
|
ApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(Config.class)
|
||||||
|
.withPropertyValues("foo.primary.name:foo1", "foo.secondary.name:foo2", "only.bar.name:solo1");
|
||||||
|
contextRunner.run((context) -> {
|
||||||
|
ConfigurationPropertiesReportEndpoint endpoint = context
|
||||||
|
.getBean(ConfigurationPropertiesReportEndpoint.class);
|
||||||
|
ApplicationConfigurationProperties applicationProperties = endpoint.configurationProperties("only.bar");
|
||||||
|
assertThat(applicationProperties.getContexts()).containsOnlyKeys(context.getId());
|
||||||
|
ContextConfigurationProperties contextProperties = applicationProperties.getContexts().get(context.getId());
|
||||||
|
assertThat(contextProperties.getBeans().values()).hasSize(1).first().hasFieldOrPropertyWithValue("prefix",
|
||||||
|
"only.bar");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void filterByPrefixMultipleMatches() {
|
||||||
|
ApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(Config.class)
|
||||||
|
.withPropertyValues("foo.primary.name:foo1", "foo.secondary.name:foo2", "only.bar.name:solo1");
|
||||||
|
contextRunner.run((context) -> {
|
||||||
|
ConfigurationPropertiesReportEndpoint endpoint = context
|
||||||
|
.getBean(ConfigurationPropertiesReportEndpoint.class);
|
||||||
|
ApplicationConfigurationProperties applicationProperties = endpoint.configurationProperties("foo.");
|
||||||
|
assertThat(applicationProperties.getContexts()).containsOnlyKeys(context.getId());
|
||||||
|
ContextConfigurationProperties contextProperties = applicationProperties.getContexts().get(context.getId());
|
||||||
|
assertThat(contextProperties.getBeans()).containsOnlyKeys("primaryFoo", "secondaryFoo");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void filterByPrefixNoMatches() {
|
||||||
|
ApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(Config.class)
|
||||||
|
.withPropertyValues("foo.primary.name:foo1", "foo.secondary.name:foo2", "only.bar.name:solo1");
|
||||||
|
contextRunner.run((context) -> {
|
||||||
|
ConfigurationPropertiesReportEndpoint endpoint = context
|
||||||
|
.getBean(ConfigurationPropertiesReportEndpoint.class);
|
||||||
|
ApplicationConfigurationProperties applicationProperties = endpoint.configurationProperties("foo.third");
|
||||||
|
assertThat(applicationProperties.getContexts()).containsOnlyKeys(context.getId());
|
||||||
|
ContextConfigurationProperties contextProperties = applicationProperties.getContexts().get(context.getId());
|
||||||
|
assertThat(contextProperties.getBeans()).isEmpty();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@EnableConfigurationProperties(Bar.class)
|
||||||
|
static class Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ConfigurationPropertiesReportEndpoint endpoint() {
|
||||||
|
return new ConfigurationPropertiesReportEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConfigurationProperties(prefix = "foo.primary")
|
||||||
|
Foo primaryFoo() {
|
||||||
|
return new Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConfigurationProperties(prefix = "foo.secondary")
|
||||||
|
Foo secondaryFoo() {
|
||||||
|
return new Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Foo {
|
||||||
|
|
||||||
|
private String name = "5150";
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigurationProperties(prefix = "only.bar")
|
||||||
|
public static class Bar {
|
||||||
|
|
||||||
|
private String name = "123456";
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2020 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.context.properties;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.boot.test.util.TestPropertyValues;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for {@link ConfigurationPropertiesReportEndpoint} exposed by Jersey,
|
||||||
|
* Spring MVC, and WebFlux.
|
||||||
|
*
|
||||||
|
* @author Chris Bono
|
||||||
|
*/
|
||||||
|
class ConfigurationPropertiesReportEndpointWebIntegrationTests {
|
||||||
|
|
||||||
|
private WebTestClient client;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void prepareEnvironment(ConfigurableApplicationContext context, WebTestClient client) {
|
||||||
|
TestPropertyValues.of("com.foo.name=fooz", "com.bar.name=barz").applyTo(context);
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@WebEndpointTest
|
||||||
|
void noFilters() {
|
||||||
|
this.client.get().uri("/actuator/configprops").exchange().expectStatus().isOk().expectBody()
|
||||||
|
.jsonPath("$..beans[*]").value(hasSize(greaterThanOrEqualTo(2))).jsonPath("$..beans['fooDotCom']")
|
||||||
|
.exists().jsonPath("$..beans['barDotCom']").exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@WebEndpointTest
|
||||||
|
void filterByExactPrefix() {
|
||||||
|
this.client.get().uri("/actuator/configprops/com.foo").exchange().expectStatus().isOk().expectBody()
|
||||||
|
.jsonPath("$..beans[*]").value(hasSize(1)).jsonPath("$..beans['fooDotCom']").exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@WebEndpointTest
|
||||||
|
void filterByGeneralPrefix() {
|
||||||
|
this.client.get().uri("/actuator/configprops/com.").exchange().expectStatus().isOk().expectBody()
|
||||||
|
.jsonPath("$..beans[*]").value(hasSize(2)).jsonPath("$..beans['fooDotCom']").exists()
|
||||||
|
.jsonPath("$..beans['barDotCom']").exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@WebEndpointTest
|
||||||
|
void filterByNonExistentPrefix() {
|
||||||
|
this.client.get().uri("/actuator/configprops/com.zoo").exchange().expectStatus().isNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@EnableConfigurationProperties
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ConfigurationPropertiesReportEndpoint endpoint() {
|
||||||
|
return new ConfigurationPropertiesReportEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ConfigurationPropertiesReportEndpointWebExtension endpointWebExtension(
|
||||||
|
ConfigurationPropertiesReportEndpoint endpoint) {
|
||||||
|
return new ConfigurationPropertiesReportEndpointWebExtension(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConfigurationProperties(prefix = "com.foo")
|
||||||
|
Foo fooDotCom() {
|
||||||
|
return new Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConfigurationProperties(prefix = "com.bar")
|
||||||
|
Bar barDotCom() {
|
||||||
|
return new Bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Foo {
|
||||||
|
|
||||||
|
private String name = "5150";
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Bar {
|
||||||
|
|
||||||
|
private String name = "6160";
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue