From d254c6271253c57383e351998ffdd97b2d385c99 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 22 Oct 2019 14:27:25 +0200 Subject: [PATCH] Polish tests --- ...gurationPropertiesReportEndpointTests.java | 537 +++++++++--------- 1 file changed, 277 insertions(+), 260 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java index cd9e316bf5..4c1de2f7d9 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java @@ -19,12 +19,12 @@ package org.springframework.boot.actuate.context.properties; import java.net.URI; import java.time.Duration; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.BiConsumer; +import java.util.Optional; +import java.util.function.Consumer; import org.junit.jupiter.api.Test; @@ -32,12 +32,12 @@ import org.springframework.boot.actuate.context.properties.ConfigurationProperti 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.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.context.ApplicationContext; +import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; +import org.springframework.core.env.Environment; import static org.assertj.core.api.Assertions.assertThat; @@ -51,207 +51,177 @@ import static org.assertj.core.api.Assertions.assertThat; */ class ConfigurationPropertiesReportEndpointTests { + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(EndpointConfig.class); + @Test - void configurationPropertiesAreReturned() { - load((context, properties) -> { - assertThat(properties.getBeans().size()).isGreaterThan(0); - ConfigurationPropertiesBeanDescriptor nestedProperties = properties.getBeans().get("testProperties"); - assertThat(nestedProperties).isNotNull(); - assertThat(nestedProperties.getPrefix()).isEqualTo("test"); - assertThat(nestedProperties.getProperties()).isNotEmpty(); - }); + void descriptorDetectsRelevantProperties() { + this.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class).run(assertProperties("test", + (properties) -> assertThat(properties).containsOnlyKeys("dbPassword", "myTestProperty", "duration"))); } @Test - void entriesWithNullValuesAreNotIncluded() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties).doesNotContainKey("nullValue"); - }); + void descriptorDoesNotIncludePropertyWithNullValue() { + this.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class) + .run(assertProperties("test", (properties) -> assertThat(properties).doesNotContainKey("nullValue"))); } @Test - void defaultKeySanitization() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties).isNotNull(); - assertThat(nestedProperties.get("dbPassword")).isEqualTo("******"); - assertThat(nestedProperties.get("myTestProperty")).isEqualTo("654321"); - }); + void descriptorWithDurationProperty() { + this.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class).run(assertProperties("test", + (properties) -> assertThat(properties.get("duration")).isEqualTo(Duration.ofSeconds(10).toString()))); } @Test - void customKeySanitization() { - load("property", (context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties).isNotNull(); - assertThat(nestedProperties.get("dbPassword")).isEqualTo("123456"); - assertThat(nestedProperties.get("myTestProperty")).isEqualTo("******"); - }); + void descriptorWithNonCamelCaseProperty() { + this.contextRunner.withUserConfiguration(MixedCasePropertiesConfiguration.class).run(assertProperties( + "mixedcase", (properties) -> assertThat(properties.get("myURL")).isEqualTo("https://example.com"))); } @Test - void customPatternKeySanitization() { - load(".*pass.*", (context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties).isNotNull(); - assertThat(nestedProperties.get("dbPassword")).isEqualTo("******"); - assertThat(nestedProperties.get("myTestProperty")).isEqualTo("654321"); - }); + void descriptorWithMixedCaseProperty() { + this.contextRunner.withUserConfiguration(MixedCasePropertiesConfiguration.class).run(assertProperties( + "mixedcase", (properties) -> assertThat(properties.get("mIxedCase")).isEqualTo("mixed"))); } @Test - @SuppressWarnings("unchecked") - void keySanitizationWithCustomPatternUsingCompositeKeys() { - // gh-4415 - load(Arrays.asList(".*\\.secrets\\..*", ".*\\.hidden\\..*"), (context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties).isNotNull(); - Map secrets = (Map) nestedProperties.get("secrets"); - Map hidden = (Map) nestedProperties.get("hidden"); - assertThat(secrets.get("mine")).isEqualTo("******"); - assertThat(secrets.get("yours")).isEqualTo("******"); - assertThat(hidden.get("mine")).isEqualTo("******"); - }); + void descriptorWithSingleLetterProperty() { + this.contextRunner.withUserConfiguration(MixedCasePropertiesConfiguration.class) + .run(assertProperties("mixedcase", (properties) -> assertThat(properties.get("z")).isEqualTo("zzz"))); } @Test - void nonCamelCaseProperty() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("myURL")).isEqualTo("https://example.com"); - }); + void descriptorWithSimpleBooleanProperty() { + this.contextRunner.withUserConfiguration(BooleanPropertiesConfiguration.class).run(assertProperties("boolean", + (properties) -> assertThat(properties.get("simpleBoolean")).isEqualTo(true))); } @Test - void simpleBoolean() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("simpleBoolean")).isEqualTo(true); - }); + void descriptorWithMixedBooleanProperty() { + this.contextRunner.withUserConfiguration(BooleanPropertiesConfiguration.class).run(assertProperties("boolean", + (properties) -> assertThat(properties.get("mixedBoolean")).isEqualTo(true))); } @Test - void mixedBoolean() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("mixedBoolean")).isEqualTo(true); - }); + void sanitizeWithDefaultSettings() { + this.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class) + .run(assertProperties("test", (properties) -> { + assertThat(properties.get("dbPassword")).isEqualTo("******"); + assertThat(properties.get("myTestProperty")).isEqualTo("654321"); + })); } @Test - void mixedCase() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("mIxedCase")).isEqualTo("mixed"); - }); + void sanitizeWithCustomKey() { + this.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class) + .withPropertyValues("test.keys-to-sanitize=property").run(assertProperties("test", (properties) -> { + assertThat(properties.get("dbPassword")).isEqualTo("123456"); + assertThat(properties.get("myTestProperty")).isEqualTo("******"); + })); } @Test - void duration() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("duration")).isEqualTo(Duration.ofSeconds(10).toString()); - }); + void sanitizeWithCustomKeyPattern() { + this.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class) + .withPropertyValues("test.keys-to-sanitize=.*pass.*").run(assertProperties("test", (properties) -> { + assertThat(properties.get("dbPassword")).isEqualTo("******"); + assertThat(properties.get("myTestProperty")).isEqualTo("654321"); + })); } @Test - void singleLetterProperty() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("z")).isEqualTo("zzz"); - }); - } - - @Test - @SuppressWarnings("unchecked") - void listsAreSanitized() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("listItems")).isInstanceOf(List.class); - List list = (List) nestedProperties.get("listItems"); - assertThat(list).hasSize(1); - Map item = (Map) list.get(0); - assertThat(item.get("somePassword")).isEqualTo("******"); - }); + void sanitizeWithCustomPatternUsingCompositeKeys() { + this.contextRunner.withUserConfiguration(Gh4415PropertiesConfiguration.class) + .withPropertyValues("test.keys-to-sanitize=.*\\.secrets\\..*,.*\\.hidden\\..*") + .run(assertProperties("gh4415", (properties) -> { + Map secrets = (Map) properties.get("secrets"); + Map hidden = (Map) properties.get("hidden"); + assertThat(secrets.get("mine")).isEqualTo("******"); + assertThat(secrets.get("yours")).isEqualTo("******"); + assertThat(hidden.get("mine")).isEqualTo("******"); + })); } @Test void sanitizedUriWithSensitiveInfo() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("sensitiveUri")).isEqualTo("http://user:******@localhost:8080"); - }); + this.contextRunner.withUserConfiguration(SensiblePropertiesConfiguration.class) + .run(assertProperties("sensible", (properties) -> assertThat(properties.get("sensitiveUri")) + .isEqualTo("http://user:******@localhost:8080"))); } @Test void sanitizedUriWithNoPassword() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("noPasswordUri")).isEqualTo("http://user:******@localhost:8080"); - }); + this.contextRunner.withUserConfiguration(SensiblePropertiesConfiguration.class) + .run(assertProperties("sensible", (properties) -> assertThat(properties.get("noPasswordUri")) + .isEqualTo("http://user:******@localhost:8080"))); + } + + @Test + void sanitizeLists() { + this.contextRunner.withUserConfiguration(SensiblePropertiesConfiguration.class) + .run(assertProperties("sensible", (properties) -> { + assertThat(properties.get("listItems")).isInstanceOf(List.class); + List list = (List) properties.get("listItems"); + assertThat(list).hasSize(1); + Map item = (Map) list.get(0); + assertThat(item.get("somePassword")).isEqualTo("******"); + })); } @Test - @SuppressWarnings("unchecked") void listsOfListsAreSanitized() { - load((context, properties) -> { - Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); - assertThat(nestedProperties.get("listOfListItems")).isInstanceOf(List.class); - List> listOfLists = (List>) nestedProperties.get("listOfListItems"); - assertThat(listOfLists).hasSize(1); - List list = listOfLists.get(0); - assertThat(list).hasSize(1); - Map item = (Map) list.get(0); - assertThat(item.get("somePassword")).isEqualTo("******"); - }); + this.contextRunner.withUserConfiguration(SensiblePropertiesConfiguration.class) + .run(assertProperties("sensible", (properties) -> { + assertThat(properties.get("listOfListItems")).isInstanceOf(List.class); + List> listOfLists = (List>) properties.get("listOfListItems"); + assertThat(listOfLists).hasSize(1); + List list = listOfLists.get(0); + assertThat(list).hasSize(1); + Map item = (Map) list.get(0); + assertThat(item.get("somePassword")).isEqualTo("******"); + })); } - private void load(BiConsumer properties) { - load(Collections.emptyList(), properties); - } - - private void load(String keyToSanitize, BiConsumer properties) { - load(Collections.singletonList(keyToSanitize), properties); - } - - private void load(List keysToSanitize, - BiConsumer properties) { - ApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(Config.class); - contextRunner.run((context) -> { + private ContextConsumer assertProperties(String prefix, + Consumer> properties) { + return (context) -> { ConfigurationPropertiesReportEndpoint endpoint = context .getBean(ConfigurationPropertiesReportEndpoint.class); - if (!CollectionUtils.isEmpty(keysToSanitize)) { - endpoint.setKeysToSanitize(StringUtils.toStringArray(keysToSanitize)); + ContextConfigurationProperties allProperties = endpoint.configurationProperties().getContexts() + .get(context.getId()); + Optional key = allProperties.getBeans().keySet().stream() + .filter((id) -> findIdFromPrefix(prefix, id)).findAny(); + assertThat(key).describedAs("No configuration properties with prefix '%s' found", prefix).isPresent(); + ConfigurationPropertiesBeanDescriptor descriptor = allProperties.getBeans().get(key.get()); + assertThat(descriptor.getPrefix()).isEqualTo(prefix); + properties.accept(descriptor.getProperties()); + }; + } + + private boolean findIdFromPrefix(String prefix, String id) { + int separator = id.indexOf("-"); + String candidate = (separator != -1) ? id.substring(0, separator) : id; + return prefix.equals(candidate); + } + + @Configuration(proxyBeanMethods = false) + static class EndpointConfig { + + @Bean + ConfigurationPropertiesReportEndpoint endpoint(Environment environment) { + ConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(); + String[] keys = environment.getProperty("test.keys-to-sanitize", String[].class); + if (keys != null) { + endpoint.setKeysToSanitize(keys); } - properties.accept(context, endpoint.configurationProperties().getContexts().get(context.getId())); - }); - } - - @Configuration(proxyBeanMethods = false) - @EnableConfigurationProperties - static class Parent { - - @Bean - TestProperties testProperties() { - return new TestProperties(); + return endpoint; } } @Configuration(proxyBeanMethods = false) - @EnableConfigurationProperties - static class Config { - - @Bean - ConfigurationPropertiesReportEndpoint endpoint() { - return new ConfigurationPropertiesReportEndpoint(); - } - - @Bean - TestProperties testProperties() { - return new TestProperties(); - } + @EnableConfigurationProperties(TestProperties.class) + static class TestPropertiesConfiguration { } @@ -262,39 +232,10 @@ class ConfigurationPropertiesReportEndpointTests { private String myTestProperty = "654321"; - private String myURL = "https://example.com"; - - private boolean simpleBoolean = true; - - private Boolean mixedBoolean = true; - - private String mIxedCase = "mixed"; - - private String z = "zzz"; - - private Map secrets = new HashMap<>(); - - private Hidden hidden = new Hidden(); - - private List listItems = new ArrayList<>(); - - private List> listOfListItems = new ArrayList<>(); - private String nullValue = null; private Duration duration = Duration.ofSeconds(10); - private URI sensitiveUri = URI.create("http://user:password@localhost:8080"); - - private URI noPasswordUri = URI.create("http://user:@localhost:8080"); - - TestProperties() { - this.secrets.put("mine", "myPrivateThing"); - this.secrets.put("yours", "yourPrivateThing"); - this.listItems.add(new ListItem()); - this.listOfListItems.add(Arrays.asList(new ListItem())); - } - public String getDbPassword() { return this.dbPassword; } @@ -311,78 +252,6 @@ class ConfigurationPropertiesReportEndpointTests { this.myTestProperty = myTestProperty; } - public String getMyURL() { - return this.myURL; - } - - public void setMyURL(String myURL) { - this.myURL = myURL; - } - - public boolean isSimpleBoolean() { - return this.simpleBoolean; - } - - public void setSimpleBoolean(boolean simpleBoolean) { - this.simpleBoolean = simpleBoolean; - } - - public boolean isMixedBoolean() { - return (this.mixedBoolean != null) ? this.mixedBoolean : false; - } - - public void setMixedBoolean(Boolean mixedBoolean) { - this.mixedBoolean = mixedBoolean; - } - - public String getmIxedCase() { - return this.mIxedCase; - } - - public void setmIxedCase(String mIxedCase) { - this.mIxedCase = mIxedCase; - } - - public String getZ() { - return this.z; - } - - public void setZ(String z) { - this.z = z; - } - - public Map getSecrets() { - return this.secrets; - } - - public void setSecrets(Map secrets) { - this.secrets = secrets; - } - - public Hidden getHidden() { - return this.hidden; - } - - public void setHidden(Hidden hidden) { - this.hidden = hidden; - } - - public List getListItems() { - return this.listItems; - } - - public void setListItems(List listItems) { - this.listItems = listItems; - } - - public List> getListOfListItems() { - return this.listOfListItems; - } - - public void setListOfListItems(List> listOfListItems) { - this.listOfListItems = listOfListItems; - } - public String getNullValue() { return this.nullValue; } @@ -399,6 +268,152 @@ class ConfigurationPropertiesReportEndpointTests { this.duration = duration; } + } + + @Configuration(proxyBeanMethods = false) + @EnableConfigurationProperties(MixedCaseProperties.class) + static class MixedCasePropertiesConfiguration { + + } + + @ConfigurationProperties("mixedcase") + public static class MixedCaseProperties { + + private String myURL = "https://example.com"; + + private String mIxedCase = "mixed"; + + private String z = "zzz"; + + public String getMyURL() { + return this.myURL; + } + + public void setMyURL(String myURL) { + this.myURL = myURL; + } + + public String getmIxedCase() { + return this.mIxedCase; + } + + public void setmIxedCase(String mIxedCase) { + this.mIxedCase = mIxedCase; + } + + public String getZ() { + return this.z; + } + + public void setZ(String z) { + this.z = z; + } + + } + + @Configuration(proxyBeanMethods = false) + @EnableConfigurationProperties(BooleanProperties.class) + static class BooleanPropertiesConfiguration { + + } + + @ConfigurationProperties("boolean") + public static class BooleanProperties { + + private boolean simpleBoolean = true; + + private Boolean mixedBoolean = true; + + public boolean isSimpleBoolean() { + return this.simpleBoolean; + } + + public void setSimpleBoolean(boolean simpleBoolean) { + this.simpleBoolean = simpleBoolean; + } + + public boolean isMixedBoolean() { + return (this.mixedBoolean != null) ? this.mixedBoolean : false; + } + + public void setMixedBoolean(Boolean mixedBoolean) { + this.mixedBoolean = mixedBoolean; + } + + } + + @Configuration(proxyBeanMethods = false) + @EnableConfigurationProperties(Gh4415Properties.class) + static class Gh4415PropertiesConfiguration { + + } + + @ConfigurationProperties("gh4415") + public static class Gh4415Properties { + + private Hidden hidden = new Hidden(); + + private Map secrets = new HashMap<>(); + + Gh4415Properties() { + this.secrets.put("mine", "myPrivateThing"); + this.secrets.put("yours", "yourPrivateThing"); + } + + public Hidden getHidden() { + return this.hidden; + } + + public void setHidden(Hidden hidden) { + this.hidden = hidden; + } + + public Map getSecrets() { + return this.secrets; + } + + public void setSecrets(Map secrets) { + this.secrets = secrets; + } + + public static class Hidden { + + private String mine = "mySecret"; + + public String getMine() { + return this.mine; + } + + public void setMine(String mine) { + this.mine = mine; + } + + } + + } + + @Configuration(proxyBeanMethods = false) + @EnableConfigurationProperties(SensibleProperties.class) + static class SensiblePropertiesConfiguration { + + } + + @ConfigurationProperties("sensible") + public static class SensibleProperties { + + private URI sensitiveUri = URI.create("http://user:password@localhost:8080"); + + private URI noPasswordUri = URI.create("http://user:@localhost:8080"); + + private List listItems = new ArrayList<>(); + + private List> listOfListItems = new ArrayList<>(); + + SensibleProperties() { + this.listItems.add(new ListItem()); + this.listOfListItems.add(Collections.singletonList(new ListItem())); + } + public void setSensitiveUri(URI sensitiveUri) { this.sensitiveUri = sensitiveUri; } @@ -415,18 +430,20 @@ class ConfigurationPropertiesReportEndpointTests { return this.noPasswordUri; } - public static class Hidden { + public List getListItems() { + return this.listItems; + } - private String mine = "mySecret"; + public void setListItems(List listItems) { + this.listItems = listItems; + } - public String getMine() { - return this.mine; - } - - public void setMine(String mine) { - this.mine = mine; - } + public List> getListOfListItems() { + return this.listOfListItems; + } + public void setListOfListItems(List> listOfListItems) { + this.listOfListItems = listOfListItems; } public static class ListItem {