diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/util/EnvironmentTestUtils.java b/spring-boot-test/src/main/java/org/springframework/boot/test/util/EnvironmentTestUtils.java index ecaffc7cde4..d7d23b6bbc3 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/util/EnvironmentTestUtils.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/util/EnvironmentTestUtils.java @@ -32,7 +32,9 @@ import org.springframework.core.env.MutablePropertySources; * @author Dave Syer * @author Stephane Nicoll * @since 1.4.0 + * @deprecated since 2.0.0 in favor of {@link TestPropertyValues} */ +@Deprecated public abstract class EnvironmentTestUtils { /** diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/util/TestPropertyValues.java b/spring-boot-test/src/main/java/org/springframework/boot/test/util/TestPropertyValues.java new file mode 100644 index 00000000000..ad4470a452c --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/util/TestPropertyValues.java @@ -0,0 +1,172 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.test.util; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.source.ConfigurationPropertySources; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.SystemEnvironmentPropertySource; +import org.springframework.util.Assert; + +/** + * Test utilities for adding properties to the environment. The type of {@link PropertySource} + * to be added can be specified by {@link Type}. + * + * @author Madhura Bhave + * @since 2.0.0 + */ +public final class TestPropertyValues { + + private final Map properties = new HashMap<>(); + + private TestPropertyValues(String[] pairs) { + addProperties(pairs); + } + + /** + * Return a new {@link TestPropertyValues} with the underlying map populated with the given property pairs. + * Name-value pairs can be specified with colon (":") or equals ("=") separators. + * @param pairs The key value pairs for properties that need to be added to the environment + * @return the new instance + */ + public static TestPropertyValues of(String... pairs) { + return new TestPropertyValues(pairs); + } + + /** + * Builder method to append another property to the underlying map of properties. + * @param key The property key + * @param value The property value + * @return the existing instance of {@link TestPropertyValues} + */ + public TestPropertyValues and(String key, String value) { + this.properties.put(key, value); + return this; + } + + private void addProperties(String[] pairs) { + for (String pair : pairs) { + int index = getSeparatorIndex(pair); + String key = pair.substring(0, index > 0 ? index : pair.length()); + String value = index > 0 ? pair.substring(index + 1) : ""; + this.properties.put(key.trim(), value.trim()); + } + } + + /** + * Add the properties from the underlying map to the environment owned by an {@link ApplicationContext}. + * @param context the context with an environment to modify + */ + public void applyTo(ConfigurableApplicationContext context) { + applyTo(context.getEnvironment()); + } + + /** + * Add the properties from the underlying map to the environment. The default property source used is + * {@link MapPropertySource}. + * @param environment the environment that needs to be modified + */ + public void applyTo(ConfigurableEnvironment environment) { + applyTo(environment, Type.MAP); + } + + /** + * Add the properties from the underlying map to the environment using the specified property source type. + * @param environment the environment that needs to be modified + * @param type the type of {@link PropertySource} to be added. See {@link Type} + */ + public void applyTo(ConfigurableEnvironment environment, Type type) { + applyTo(environment, type, "test"); + } + + /** + * Add the properties from the underlying map to the environment using the specified property source type and name. + * @param environment the environment that needs to be modified + * @param type the type of {@link PropertySource} to be added. See {@link Type} + * @param name the name for the property source + */ + public void applyTo(ConfigurableEnvironment environment, Type type, String name) { + Assert.notNull(environment, "Environment must not be null"); + Assert.notNull(type, "Property source type must not be null"); + Assert.notNull(name, "Property source name must not be null"); + MutablePropertySources sources = environment.getPropertySources(); + addToSources(sources, type, name); + ConfigurationPropertySources.attach(environment); + } + + @SuppressWarnings("unchecked") + private void addToSources(MutablePropertySources sources, Type type, String name) { + if (sources.contains(name)) { + PropertySource propertySource = sources.get(name); + if (propertySource.getClass().equals(type.getSourceClass())) { + Map source = (Map) propertySource.getSource(); + source.putAll(this.properties); + return; + } + } + MapPropertySource source = (type.equals(Type.MAP) ? new MapPropertySource(name, this.properties) : + new SystemEnvironmentPropertySource(name, this.properties)); + sources.addFirst(source); + } + + private static int getSeparatorIndex(String pair) { + int colonIndex = pair.indexOf(":"); + int equalIndex = pair.indexOf("="); + if (colonIndex == -1) { + return equalIndex; + } + if (equalIndex == -1) { + return colonIndex; + } + return Math.min(colonIndex, equalIndex); + } + + /** + * The type of property source. + */ + public enum Type { + + /** + * Used for {@link SystemEnvironmentPropertySource}. + */ + SYSTEM(SystemEnvironmentPropertySource.class), + + /** + * Used for {@link MapPropertySource}. + */ + MAP(MapPropertySource.class); + + private Class sourceClass; + + Type(Class sourceClass) { + this.sourceClass = sourceClass; + } + + public Class getSourceClass() { + return this.sourceClass; + } + } + +} + diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/util/TestPropertyValuesTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/util/TestPropertyValuesTests.java new file mode 100644 index 00000000000..d43364c5646 --- /dev/null +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/util/TestPropertyValuesTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.test.util; + +import org.junit.Test; + +import org.springframework.boot.test.util.TestPropertyValues.Type; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.env.SystemEnvironmentPropertySource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link TestPropertyValues}. + * + * @author Madhura Bhave + */ +public class TestPropertyValuesTests { + + private final ConfigurableEnvironment environment = new StandardEnvironment(); + + @Test + public void applyToEnvironmentShouldAttachConfigurationPropertySource() throws Exception { + TestPropertyValues.of("foo.bar=baz").applyTo(this.environment); + PropertySource source = this.environment.getPropertySources().get("configurationProperties"); + assertThat(source).isNotNull(); + } + + @Test + public void applyToDefaultPropertySource() throws Exception { + TestPropertyValues.of("foo.bar=baz", "hello.world=hi").applyTo(this.environment); + assertThat(this.environment.getProperty("foo.bar")).isEqualTo("baz"); + assertThat(this.environment.getProperty("hello.world")).isEqualTo("hi"); + } + + @Test + public void applyToSystemPropertySource() throws Exception { + TestPropertyValues.of("FOO_BAR=BAZ").applyTo(this.environment, Type.SYSTEM); + assertThat(this.environment.getProperty("foo.bar")).isEqualTo("BAZ"); + } + + @Test + public void applyToWithSpecificName() throws Exception { + TestPropertyValues.of("foo.bar=baz").applyTo(this.environment, Type.MAP, "other"); + assertThat(this.environment.getPropertySources().get("other")).isNotNull(); + assertThat(this.environment.getProperty("foo.bar")).isEqualTo("baz"); + } + + @Test + public void applyToExistingNameAndDifferentTypeShouldOverrideExistingOne() throws Exception { + TestPropertyValues.of("foo.bar=baz", "hello.world=hi").applyTo(this.environment, Type.MAP, "other"); + TestPropertyValues.of("FOO_BAR=BAZ").applyTo(this.environment, Type.SYSTEM, "other"); + assertThat(this.environment.getPropertySources().get("other")).isInstanceOf(SystemEnvironmentPropertySource.class); + assertThat(this.environment.getProperty("foo.bar")).isEqualTo("BAZ"); + assertThat(this.environment.getProperty("hello.world")).isNull(); + } + + @Test + public void applyToExistingNameAndSameTypeShouldMerge() throws Exception { + TestPropertyValues.of("foo.bar=baz", "hello.world=hi").applyTo(this.environment, Type.MAP); + TestPropertyValues.of("foo.bar=new").applyTo(this.environment, Type.MAP); + assertThat(this.environment.getProperty("foo.bar")).isEqualTo("new"); + assertThat(this.environment.getProperty("hello.world")).isEqualTo("hi"); + } + + @Test + public void andShouldChainAndAddSingleKeyValue() throws Exception { + TestPropertyValues.of("foo.bar=baz").and("hello.world", "hi").and("bling.blah", "bing") + .applyTo(this.environment, Type.MAP); + assertThat(this.environment.getProperty("foo.bar")).isEqualTo("baz"); + assertThat(this.environment.getProperty("hello.world")).isEqualTo("hi"); + assertThat(this.environment.getProperty("bling.blah")).isEqualTo("bing"); + } +}