diff --git a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java index 3e499a7cc80..824d441d2c5 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java @@ -27,6 +27,7 @@ import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; @@ -34,6 +35,7 @@ import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySources; import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePropertySource; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.util.TestContextResourceUtils; @@ -157,12 +159,8 @@ public abstract class TestPropertySourceUtils { /** * Add the {@link Properties} files from the given resource {@code locations} * to the {@link Environment} of the supplied {@code context}. - *

Property placeholders in resource locations (i.e., ${...}) - * will be {@linkplain Environment#resolveRequiredPlaceholders(String) resolved} - * against the {@code Environment}. - *

Each properties file will be converted to a {@link ResourcePropertySource} - * that will be added to the {@link PropertySources} of the environment with - * highest precedence. + *

This method simply delegates to + * {@link #addPropertiesFilesToEnvironment(ConfigurableEnvironment, ResourceLoader, String...)}. * @param context the application context whose environment should be updated; * never {@code null} * @param locations the resource locations of {@code Properties} files to add @@ -170,22 +168,50 @@ public abstract class TestPropertySourceUtils { * @since 4.1.5 * @see ResourcePropertySource * @see TestPropertySource#locations + * @see #addPropertiesFilesToEnvironment(ConfigurableEnvironment, ResourceLoader, String...) * @throws IllegalStateException if an error occurs while processing a properties file */ - public static void addPropertiesFilesToEnvironment(ConfigurableApplicationContext context, - String... locations) { + public static void addPropertiesFilesToEnvironment(ConfigurableApplicationContext context, String... locations) { Assert.notNull(context, "context must not be null"); Assert.notNull(locations, "locations must not be null"); + addPropertiesFilesToEnvironment(context.getEnvironment(), context, locations); + } + + /** + * Add the {@link Properties} files from the given resource {@code locations} + * to the supplied {@link ConfigurableEnvironment environment}. + *

Property placeholders in resource locations (i.e., ${...}) + * will be {@linkplain Environment#resolveRequiredPlaceholders(String) resolved} + * against the {@code Environment}. + *

Each properties file will be converted to a {@link ResourcePropertySource} + * that will be added to the {@link PropertySources} of the environment with + * highest precedence. + * @param environment the environment to update; never {@code null} + * @param resourceLoader the {@code ResourceLoader} to use to load each resource; + * never {@code null} + * @param locations the resource locations of {@code Properties} files to add + * to the environment; potentially empty but never {@code null} + * @since 4.3 + * @see ResourcePropertySource + * @see TestPropertySource#locations + * @see #addPropertiesFilesToEnvironment(ConfigurableApplicationContext, String...) + * @throws IllegalStateException if an error occurs while processing a properties file + */ + public static void addPropertiesFilesToEnvironment(ConfigurableEnvironment environment, + ResourceLoader resourceLoader, String... locations) { + + Assert.notNull(environment, "environment must not be null"); + Assert.notNull(resourceLoader, "resourceLoader must not be null"); + Assert.notNull(locations, "locations must not be null"); try { - ConfigurableEnvironment environment = context.getEnvironment(); for (String location : locations) { String resolvedLocation = environment.resolveRequiredPlaceholders(location); - Resource resource = context.getResource(resolvedLocation); + Resource resource = resourceLoader.getResource(resolvedLocation); environment.getPropertySources().addFirst(new ResourcePropertySource(resource)); } } - catch (IOException e) { - throw new IllegalStateException("Failed to add PropertySource to Environment", e); + catch (IOException ex) { + throw new IllegalStateException("Failed to add PropertySource to Environment", ex); } } diff --git a/spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java b/spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java index e6c41b5f8df..48ab1990cf1 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java @@ -26,13 +26,17 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.annotation.AnnotationConfigurationException; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.ResourceLoader; import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockPropertySource; import org.springframework.test.context.TestPropertySource; import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.CoreMatchers.startsWith; import static org.junit.Assert.*; -import static org.mockito.Mockito.mock; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; import static org.springframework.test.context.support.TestPropertySourceUtils.*; /** @@ -45,19 +49,12 @@ public class TestPropertySourceUtilsTests { private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final String[] KEY_VALUE_PAIR = new String[] { "key = value" }; + private static final String[] FOO_LOCATIONS = new String[] { "classpath:/foo.properties" }; @Rule public ExpectedException expectedException = ExpectedException.none(); - private void assertMergedTestPropertySources(Class testClass, String[] expectedLocations, - String[] expectedProperties) { - MergedTestPropertySources mergedPropertySources = buildMergedTestPropertySources(testClass); - assertNotNull(mergedPropertySources); - assertArrayEquals(expectedLocations, mergedPropertySources.getLocations()); - assertArrayEquals(expectedProperties, mergedPropertySources.getProperties()); - } - @Test public void emptyAnnotation() { expectedException.expect(IllegalStateException.class); @@ -76,7 +73,7 @@ public class TestPropertySourceUtilsTests { @Test public void value() { - assertMergedTestPropertySources(ValuePropertySources.class, new String[] { "classpath:/value.xml" }, + assertMergedTestPropertySources(ValuePropertySources.class, asArray("classpath:/value.xml"), EMPTY_STRING_ARRAY); } @@ -88,44 +85,91 @@ public class TestPropertySourceUtilsTests { @Test public void locationsAndProperties() { - assertMergedTestPropertySources(LocationsAndPropertiesPropertySources.class, new String[] { - "classpath:/foo1.xml", "classpath:/foo2.xml" }, new String[] { "k1a=v1a", "k1b: v1b" }); + assertMergedTestPropertySources(LocationsAndPropertiesPropertySources.class, + asArray("classpath:/foo1.xml", "classpath:/foo2.xml"), asArray("k1a=v1a", "k1b: v1b")); } @Test public void inheritedLocationsAndProperties() { - assertMergedTestPropertySources(InheritedPropertySources.class, new String[] { "classpath:/foo1.xml", - "classpath:/foo2.xml" }, new String[] { "k1a=v1a", "k1b: v1b" }); + assertMergedTestPropertySources(InheritedPropertySources.class, + asArray("classpath:/foo1.xml", "classpath:/foo2.xml"), asArray("k1a=v1a", "k1b: v1b")); } @Test public void extendedLocationsAndProperties() { - assertMergedTestPropertySources(ExtendedPropertySources.class, new String[] { "classpath:/foo1.xml", - "classpath:/foo2.xml", "classpath:/bar1.xml", "classpath:/bar2.xml" }, new String[] { "k1a=v1a", - "k1b: v1b", "k2a v2a", "k2b: v2b" }); + assertMergedTestPropertySources(ExtendedPropertySources.class, + asArray("classpath:/foo1.xml", "classpath:/foo2.xml", "classpath:/bar1.xml", "classpath:/bar2.xml"), + asArray("k1a=v1a", "k1b: v1b", "k2a v2a", "k2b: v2b")); } @Test public void overriddenLocations() { assertMergedTestPropertySources(OverriddenLocationsPropertySources.class, - new String[] { "classpath:/baz.properties" }, new String[] { "k1a=v1a", "k1b: v1b", "key = value" }); + asArray("classpath:/baz.properties"), asArray("k1a=v1a", "k1b: v1b", "key = value")); } @Test public void overriddenProperties() { - assertMergedTestPropertySources(OverriddenPropertiesPropertySources.class, new String[] { - "classpath:/foo1.xml", "classpath:/foo2.xml", "classpath:/baz.properties" }, KEY_VALUE_PAIR); + assertMergedTestPropertySources(OverriddenPropertiesPropertySources.class, + asArray("classpath:/foo1.xml", "classpath:/foo2.xml", "classpath:/baz.properties"), KEY_VALUE_PAIR); } @Test public void overriddenLocationsAndProperties() { assertMergedTestPropertySources(OverriddenLocationsAndPropertiesPropertySources.class, - new String[] { "classpath:/baz.properties" }, KEY_VALUE_PAIR); + asArray("classpath:/baz.properties"), KEY_VALUE_PAIR); } - /** - * @since 4.1.5 - */ + // ------------------------------------------------------------------------- + + @Test + public void addPropertiesFilesToEnvironmentWithNullContext() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("context must not be null"); + addPropertiesFilesToEnvironment((ConfigurableApplicationContext) null, FOO_LOCATIONS); + } + + @Test + public void addPropertiesFilesToEnvironmentWithContextAndNullLocations() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("locations must not be null"); + addPropertiesFilesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null); + } + + @Test + public void addPropertiesFilesToEnvironmentWithNullEnvironment() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("environment must not be null"); + addPropertiesFilesToEnvironment((ConfigurableEnvironment) null, mock(ResourceLoader.class), FOO_LOCATIONS); + } + + @Test + public void addPropertiesFilesToEnvironmentWithEnvironmentAndNullLocations() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("locations must not be null"); + addPropertiesFilesToEnvironment(new MockEnvironment(), mock(ResourceLoader.class), (String[]) null); + } + + @Test + public void addPropertiesFilesToEnvironmentWithSinglePropertyFromVirtualFile() { + ConfigurableEnvironment environment = new MockEnvironment(); + + MutablePropertySources propertySources = environment.getPropertySources(); + propertySources.remove(MockPropertySource.MOCK_PROPERTIES_PROPERTY_SOURCE_NAME); + assertEquals(0, propertySources.size()); + + String pair = "key = value"; + ByteArrayResource resource = new ByteArrayResource(pair.getBytes(), "from inlined property: " + pair); + ResourceLoader resourceLoader = mock(ResourceLoader.class); + when(resourceLoader.getResource(anyString())).thenReturn(resource); + + addPropertiesFilesToEnvironment(environment, resourceLoader, FOO_LOCATIONS); + assertEquals(1, propertySources.size()); + assertEquals("value", environment.getProperty("key")); + } + + // ------------------------------------------------------------------------- + @Test public void addInlinedPropertiesToEnvironmentWithNullContext() { expectedException.expect(IllegalArgumentException.class); @@ -133,9 +177,6 @@ public class TestPropertySourceUtilsTests { addInlinedPropertiesToEnvironment((ConfigurableApplicationContext) null, KEY_VALUE_PAIR); } - /** - * @since 4.1.5 - */ @Test public void addInlinedPropertiesToEnvironmentWithContextAndNullInlinedProperties() { expectedException.expect(IllegalArgumentException.class); @@ -143,9 +184,6 @@ public class TestPropertySourceUtilsTests { addInlinedPropertiesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null); } - /** - * @since 4.1.5 - */ @Test public void addInlinedPropertiesToEnvironmentWithNullEnvironment() { expectedException.expect(IllegalArgumentException.class); @@ -153,9 +191,6 @@ public class TestPropertySourceUtilsTests { addInlinedPropertiesToEnvironment((ConfigurableEnvironment) null, KEY_VALUE_PAIR); } - /** - * @since 4.1.5 - */ @Test public void addInlinedPropertiesToEnvironmentWithEnvironmentAndNullInlinedProperties() { expectedException.expect(IllegalArgumentException.class); @@ -163,29 +198,20 @@ public class TestPropertySourceUtilsTests { addInlinedPropertiesToEnvironment(new MockEnvironment(), (String[]) null); } - /** - * @since 4.1.5 - */ @Test public void addInlinedPropertiesToEnvironmentWithMalformedUnicodeInValue() { expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Failed to load test environment property"); - addInlinedPropertiesToEnvironment(new MockEnvironment(), new String[] { "key = \\uZZZZ" }); + addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("key = \\uZZZZ")); } - /** - * @since 4.1.5 - */ @Test public void addInlinedPropertiesToEnvironmentWithMultipleKeyValuePairsInSingleInlinedProperty() { expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Failed to load exactly one test environment property"); - addInlinedPropertiesToEnvironment(new MockEnvironment(), new String[] { "a=b\nx=y" }); + addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("a=b\nx=y")); } - /** - * @since 4.1.5 - */ @Test @SuppressWarnings("rawtypes") public void addInlinedPropertiesToEnvironmentWithEmptyProperty() { @@ -193,7 +219,7 @@ public class TestPropertySourceUtilsTests { MutablePropertySources propertySources = environment.getPropertySources(); propertySources.remove(MockPropertySource.MOCK_PROPERTIES_PROPERTY_SOURCE_NAME); assertEquals(0, propertySources.size()); - addInlinedPropertiesToEnvironment(environment, new String[] { " " }); + addInlinedPropertiesToEnvironment(environment, asArray(" ")); assertEquals(1, propertySources.size()); assertEquals(0, ((Map) propertySources.iterator().next().getSource()).size()); } @@ -207,6 +233,20 @@ public class TestPropertySourceUtilsTests { // ------------------------------------------------------------------- + private static void assertMergedTestPropertySources(Class testClass, String[] expectedLocations, + String[] expectedProperties) { + MergedTestPropertySources mergedPropertySources = buildMergedTestPropertySources(testClass); + assertNotNull(mergedPropertySources); + assertArrayEquals(expectedLocations, mergedPropertySources.getLocations()); + assertArrayEquals(expectedProperties, mergedPropertySources.getProperties()); + } + + @SafeVarargs + private static T[] asArray(T... arr) { + return arr; + } + + @TestPropertySource static class EmptyPropertySources { }