Filter properties with a particular prefix
This commit improves the configprops endpoint to allow filtering properties based on a particular prefix See gh-24718pull/25178/head
parent
0f9fb13141
commit
ad7c69a9cd
@ -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