diff --git a/spring-test/src/main/java/org/springframework/test/context/TestPropertySource.java b/spring-test/src/main/java/org/springframework/test/context/TestPropertySource.java index 150604e72b1..b42e2649bb0 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestPropertySource.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestPropertySource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-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. @@ -19,6 +19,7 @@ package org.springframework.test.context; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -67,6 +68,8 @@ import org.springframework.core.annotation.AliasFor; *
Note, however, that use of the {@code @TestPropertySources} container is + * completely optional since {@code @TestPropertySource} is a + * {@linkplain java.lang.annotation.Repeatable repeatable} annotation. + * + * @author Anatoliy Korovin + * @author Sam Brannen + * @since 5.2 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface TestPropertySources { + + /** + * An array of one or more {@link TestPropertySource @TestPropertySource} + * declarations. + */ + TestPropertySource[] value(); + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java index cf344885395..e07edfc602c 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java @@ -16,25 +16,19 @@ package org.springframework.test.context.support; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import java.util.List; -import org.springframework.core.io.ClassPathResource; import org.springframework.core.style.ToStringCreator; -import org.springframework.lang.Nullable; import org.springframework.test.context.TestPropertySource; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; -import org.springframework.util.ResourceUtils; /** - * {@code TestPropertySourceAttributes} encapsulates the attributes declared - * via {@link TestPropertySource @TestPropertySource}. + * {@code TestPropertySourceAttributes} encapsulates attributes declared + * via {@link TestPropertySource @TestPropertySource} annotations. * *
In addition to encapsulating declared attributes,
- * {@code TestPropertySourceAttributes} also enforces configuration rules
- * and detects default properties files.
+ * {@code TestPropertySourceAttributes} also enforces configuration rules.
*
* @author Sam Brannen
* @since 4.1
@@ -43,8 +37,6 @@ import org.springframework.util.ResourceUtils;
*/
class TestPropertySourceAttributes {
- private static final Log logger = LogFactory.getLog(TestPropertySourceAttributes.class);
-
private final Class> declaringClass;
private final String[] locations;
@@ -57,27 +49,29 @@ class TestPropertySourceAttributes {
/**
- * Create a new {@code TestPropertySourceAttributes} instance for the
- * supplied {@link TestPropertySource @TestPropertySource} annotation and
- * the {@linkplain Class test class} that declared it, enforcing
- * configuration rules and detecting a default properties file if
- * necessary.
+ * Create a new {@code TestPropertySourceAttributes} instance for the supplied
+ * values and enforce configuration rules.
* @param declaringClass the class that declared {@code @TestPropertySource}
- * @param testPropertySource the annotation from which to retrieve the attributes
- * @since 4.2
+ * @param locations the merged {@link TestPropertySource#locations()}
+ * @param inheritLocations the {@link TestPropertySource#inheritLocations()} flag
+ * @param properties the merged {@link TestPropertySource#properties()}
+ * @param inheritProperties the {@link TestPropertySource#inheritProperties()} flag
+ * @since 5.2
*/
- TestPropertySourceAttributes(Class> declaringClass, TestPropertySource testPropertySource) {
- this(declaringClass, testPropertySource.locations(), testPropertySource.inheritLocations(),
- testPropertySource.properties(), testPropertySource.inheritProperties());
+ TestPropertySourceAttributes(Class> declaringClass, List Note: The returned value may represent a detected default
- * that does not match the original value declared via {@code @TestPropertySource}.
+ * or merged locations that do not match the original value declared via a
+ * single {@code @TestPropertySource} annotation.
* @return the resource locations; potentially empty
* @see TestPropertySource#value
* @see TestPropertySource#locations
@@ -117,10 +112,12 @@ class TestPropertySourceAttributes {
/**
* Get the inlined properties that were declared via {@code @TestPropertySource}.
- * @return the inlined properties; potentially {@code null} or empty
+ * Note: The returned value may represent merged properties that do not
+ * match the original value declared via a single {@code @TestPropertySource}
+ * annotation.
+ * @return the inlined properties; potentially empty
* @see TestPropertySource#properties
*/
- @Nullable
String[] getProperties() {
return this.properties;
}
@@ -149,31 +146,4 @@ class TestPropertySourceAttributes {
.toString();
}
-
- /**
- * Detect a default properties file for the supplied class, as specified
- * in the class-level Javadoc for {@link TestPropertySource}.
- */
- private static String detectDefaultPropertiesFile(Class> testClass) {
- String resourcePath = ClassUtils.convertClassNameToResourcePath(testClass.getName()) + ".properties";
- ClassPathResource classPathResource = new ClassPathResource(resourcePath);
-
- if (classPathResource.exists()) {
- String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + resourcePath;
- if (logger.isInfoEnabled()) {
- logger.info(String.format("Detected default properties file \"%s\" for test class [%s]",
- prefixedResourcePath, testClass.getName()));
- }
- return prefixedResourcePath;
- }
- else {
- String msg = String.format("Could not detect default properties file for test [%s]: " +
- "%s does not exist. Either declare the 'locations' or 'properties' attributes " +
- "of @TestPropertySource or make the default properties file available.", testClass.getName(),
- classPathResource);
- logger.error(msg);
- throw new IllegalStateException(msg);
- }
- }
-
}
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 41574d9169a..31d6395e9ff 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-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.
@@ -20,32 +20,39 @@ import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.annotation.MergedAnnotation;
+import org.springframework.core.annotation.MergedAnnotations;
+import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources;
+import org.springframework.core.io.ClassPathResource;
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;
-import org.springframework.test.util.MetaAnnotationUtils.AnnotationDescriptor;
import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
+import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
-import static org.springframework.test.util.MetaAnnotationUtils.findAnnotationDescriptor;
-
/**
* Utility methods for working with {@link TestPropertySource @TestPropertySource}
* and adding test {@link PropertySource PropertySources} to the {@code Environment}.
@@ -53,6 +60,7 @@ import static org.springframework.test.util.MetaAnnotationUtils.findAnnotationDe
* Primarily intended for use within the framework.
*
* @author Sam Brannen
+ * @author Anatoliy Korovin
* @since 4.1
* @see TestPropertySource
*/
@@ -67,47 +75,152 @@ public abstract class TestPropertySourceUtils {
private static final Log logger = LogFactory.getLog(TestPropertySourceUtils.class);
+ /**
+ * Compares {@link MergedAnnotation} instances (presumably within the same
+ * aggregate index) by their meta-distance, in reverse order.
+ * Using this {@link Comparator} to sort according to reverse meta-distance
+ * ensures that directly present annotations take precedence over meta-present
+ * annotations (within a given aggregate index). In other words, this follows
+ * the last-one-wins principle of overriding properties.
+ * @see MergedAnnotation#getAggregateIndex()
+ * @see MergedAnnotation#getDistance()
+ */
+ private static final Comparator super MergedAnnotation>> reversedMetaDistanceComparator =
+ Comparator. Within the supplied list, sort according to reversed meta-distance of
+ * the annotations from the declaring class. This ensures that directly present
+ * annotations take precedence over meta-present annotations within the current
+ * aggregate index.
+ * If a given {@link TestPropertySource @TestPropertySource} does not
+ * declare properties or locations, an attempt will be made to detect a default
+ * properties file.
+ */
+ private static TestPropertySourceAttributes createTestPropertySourceAttributes(
+ List Note that tests included in this suite will be executed at least twice if
+ * run from an automated build process, test runner, etc. that is not configured
+ * to exclude tests based on a {@code "*TestSuite.class"} pattern match.
+ *
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@RunWith(JUnitPlatform.class)
+@IncludeEngines("junit-vintage")
+@SelectPackages("org.springframework.test.context.env")
+@IncludeClassNamePatterns(".*Tests$")
+@UseTechnicalNames
+public class TestPropertySourceTestSuite {
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractClassWithTestProperty.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractClassWithTestProperty.java
new file mode 100644
index 00000000000..50148f3e22b
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractClassWithTestProperty.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Abstract base class which declares an inlined property via
+ * {@link TestPropertySource @TestPropertySource}.
+ *
+ * @author Anatoliy Korovin
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource(properties = "key1 = parent")
+abstract class AbstractClassWithTestProperty extends AbstractRepeatableTestPropertySourceTests {
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractRepeatableTestPropertySourceTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractRepeatableTestPropertySourceTests.java
new file mode 100644
index 00000000000..2f180aaa057
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractRepeatableTestPropertySourceTests.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Abstract base class for integration tests involving
+ * {@link TestPropertySource @TestPropertySource} as a repeatable annotation.
+ *
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+abstract class AbstractRepeatableTestPropertySourceTests {
+
+ @Autowired
+ Environment env;
+
+
+ protected void assertEnvironmentValue(String key, String expected) {
+ assertThat(env.getProperty(key)).as("Value of key [" + key + "].").isEqualTo(expected);
+ }
+
+
+ @Configuration
+ static class Config {
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/DefaultPropertiesFileDetectionRepeatedTestPropertySourceTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/DefaultPropertiesFileDetectionRepeatedTestPropertySourceTests.java
new file mode 100644
index 00000000000..ea55266e84e
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/DefaultPropertiesFileDetectionRepeatedTestPropertySourceTests.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Integration tests for {@link TestPropertySource @TestPropertySource} as a
+ * repeatable annotation.
+ *
+ * @author Anatoliy Korovin
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource
+@TestPropertySource("local.properties")
+public class DefaultPropertiesFileDetectionRepeatedTestPropertySourceTests
+ extends AbstractRepeatableTestPropertySourceTests {
+
+ @Test
+ public void test() {
+ assertEnvironmentValue("default.value", "default file");
+ assertEnvironmentValue("key1", "local file");
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/ExplicitPropertiesFilesRepeatedTestPropertySourceTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/ExplicitPropertiesFilesRepeatedTestPropertySourceTests.java
new file mode 100644
index 00000000000..8cbf68ce03e
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/ExplicitPropertiesFilesRepeatedTestPropertySourceTests.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Integration tests for {@link TestPropertySource @TestPropertySource} as a
+ * repeatable annotation.
+ *
+ * Same as {@link ReversedExplicitPropertiesFilesRepeatedTestPropertySourceTests},
+ * but with the order of the properties files reversed.
+ *
+ * @author Anatoliy Korovin
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource("first.properties")
+@TestPropertySource("second.properties")
+public class ExplicitPropertiesFilesRepeatedTestPropertySourceTests extends AbstractRepeatableTestPropertySourceTests {
+
+ @Test
+ public void test() {
+ assertEnvironmentValue("alpha", "omega");
+ assertEnvironmentValue("first", "1111");
+ assertEnvironmentValue("second", "2222");
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndInheritedInlinedPropertyTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndInheritedInlinedPropertyTests.java
new file mode 100644
index 00000000000..ddfbd1b4c64
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndInheritedInlinedPropertyTests.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Integration tests for {@link TestPropertySource @TestPropertySource} as a
+ * repeatable annotation.
+ *
+ * @author Anatoliy Korovin
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource(properties = "key2 = local")
+public class LocalInlinedPropertyAndInheritedInlinedPropertyTests extends AbstractClassWithTestProperty {
+
+ @Test
+ public void test() {
+ assertEnvironmentValue("key1", "parent");
+ assertEnvironmentValue("key2", "local");
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndMetaInlinedPropertyTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndMetaInlinedPropertyTests.java
new file mode 100644
index 00000000000..cc2de58efaf
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndMetaInlinedPropertyTests.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Integration tests for {@link TestPropertySource @TestPropertySource} as a
+ * repeatable annotation.
+ *
+ * @author Anatoliy Korovin
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource(properties = "key1 = local")
+@MetaInlinedTestProperty
+public class LocalInlinedPropertyAndMetaInlinedPropertyTests extends AbstractRepeatableTestPropertySourceTests {
+
+ @Test
+ public void test() {
+ assertEnvironmentValue("key1", "local");
+ assertEnvironmentValue("meta", "inlined");
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedAndMetaInlinedPropertiesTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedAndMetaInlinedPropertiesTests.java
new file mode 100644
index 00000000000..5c221a59be6
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedAndMetaInlinedPropertiesTests.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.env.repeatable.LocalInlinedPropertyOverridesInheritedAndMetaInlinedPropertiesTests.Key1InlinedTestProperty;
+
+/**
+ * Integration tests for {@link TestPropertySource @TestPropertySource} as a
+ * repeatable annotation.
+ *
+ * @author Anatoliy Korovin
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource(properties = "key1 = local")
+@Key1InlinedTestProperty
+public class LocalInlinedPropertyOverridesInheritedAndMetaInlinedPropertiesTests extends AbstractClassWithTestProperty {
+
+ @Test
+ public void test() {
+ assertEnvironmentValue("key1", "local");
+ }
+
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @TestPropertySource(properties = "key1 = meta")
+ @interface Key1InlinedTestProperty {
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedInlinedPropertyTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedInlinedPropertyTests.java
new file mode 100644
index 00000000000..b5c42216c73
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedInlinedPropertyTests.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Integration tests for {@link TestPropertySource @TestPropertySource} as a
+ * repeatable annotation.
+ *
+ * @author Anatoliy Korovin
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource(properties = "key1 = local value")
+@TestPropertySource(properties = "second = local override")
+public class LocalInlinedPropertyOverridesInheritedInlinedPropertyTests extends RepeatedTestPropertySourceTests {
+
+ @Test
+ @Override
+ public void test() {
+ assertEnvironmentValue("key1", "local value");
+ assertEnvironmentValue("second", "local override");
+ assertEnvironmentValue("first", "repeated override");
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesMetaInlinedPropertyTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesMetaInlinedPropertyTests.java
new file mode 100644
index 00000000000..55c0eec441d
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesMetaInlinedPropertyTests.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Integration tests for {@link TestPropertySource @TestPropertySource} as a
+ * repeatable annotation.
+ *
+ * @author Anatoliy Korovin
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource(properties = "meta = local override")
+@MetaInlinedTestProperty
+public class LocalInlinedPropertyOverridesMetaInlinedPropertyTests extends AbstractRepeatableTestPropertySourceTests {
+
+ @Test
+ public void test() {
+ assertEnvironmentValue("meta", "local override");
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalPropertiesFileAndMetaPropertiesFileTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalPropertiesFileAndMetaPropertiesFileTests.java
new file mode 100644
index 00000000000..c488ff2bfe3
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalPropertiesFileAndMetaPropertiesFileTests.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.env.repeatable.LocalPropertiesFileAndMetaPropertiesFileTests.MetaFileTestProperty;
+
+/**
+ * Integration tests for {@link TestPropertySource @TestPropertySource} as a
+ * repeatable annotation.
+ *
+ * Verify a property value is defined both in the properties file which is declared
+ * via {@link MetaFileTestProperty @MetaFileTestProperty} and in the properties file
+ * which is declared locally via {@code @TestPropertySource}.
+ *
+ * @author Anatoliy Korovin
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource("local.properties")
+@MetaFileTestProperty
+public class LocalPropertiesFileAndMetaPropertiesFileTests extends AbstractRepeatableTestPropertySourceTests {
+
+ @Test
+ public void test() {
+ assertEnvironmentValue("key1", "local file");
+ assertEnvironmentValue("key2", "meta file");
+ }
+
+
+ /**
+ * Composed annotation that declares a properties file via
+ * {@link TestPropertySource @TestPropertySource}.
+ */
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @TestPropertySource("meta.properties")
+ @interface MetaFileTestProperty {
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/MetaInlinedTestProperty.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/MetaInlinedTestProperty.java
new file mode 100644
index 00000000000..6e52a36bad0
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/MetaInlinedTestProperty.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Composed annotation that declares a {@code meta} inlined property via
+ * {@link TestPropertySource @TestPropertySource}.
+ *
+ * @author Anatoliy Korovin
+ * @since 5.2
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@TestPropertySource(properties = "meta = inlined")
+@interface MetaInlinedTestProperty {
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/RepeatedTestPropertySourceTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/RepeatedTestPropertySourceTests.java
new file mode 100644
index 00000000000..cf2de51822e
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/RepeatedTestPropertySourceTests.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Integration tests for {@link TestPropertySource @TestPropertySource} as a
+ * repeatable annotation.
+ *
+ * Tests multiple local {@link TestPropertySource} declarations.
+ *
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource(properties = "first = repeated")
+@TestPropertySource(properties = "second = repeated")
+@TestPropertySource(properties = "first = repeated override")
+public class RepeatedTestPropertySourceTests extends AbstractRepeatableTestPropertySourceTests {
+
+ @Test
+ public void test() {
+ assertEnvironmentValue("first", "repeated override");
+ assertEnvironmentValue("second", "repeated");
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/repeatable/ReversedExplicitPropertiesFilesRepeatedTestPropertySourceTests.java b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/ReversedExplicitPropertiesFilesRepeatedTestPropertySourceTests.java
new file mode 100644
index 00000000000..800f86f0019
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/env/repeatable/ReversedExplicitPropertiesFilesRepeatedTestPropertySourceTests.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-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.test.context.env.repeatable;
+
+import org.junit.Test;
+
+import org.springframework.test.context.TestPropertySource;
+
+/**
+ * Same as {@link ExplicitPropertiesFilesRepeatedTestPropertySourceTests}, but
+ * with the order of the properties files reversed.
+ *
+ * @author Sam Brannen
+ * @since 5.2
+ */
+@TestPropertySource("second.properties")
+@TestPropertySource("first.properties")
+public class ReversedExplicitPropertiesFilesRepeatedTestPropertySourceTests extends AbstractRepeatableTestPropertySourceTests {
+
+ @Test
+ public void test() {
+ assertEnvironmentValue("alpha", "beta");
+ assertEnvironmentValue("first", "1111");
+ assertEnvironmentValue("second", "1111");
+ }
+
+}
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 9df2b646329..d000e7b253b 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
@@ -57,23 +57,40 @@ public class TestPropertySourceUtilsTests {
private static final String[] FOO_LOCATIONS = new String[] {"classpath:/foo.properties"};
-
@Test
public void emptyAnnotation() {
- assertThatIllegalStateException().isThrownBy(() ->
- buildMergedTestPropertySources(EmptyPropertySources.class))
- .withMessageStartingWith("Could not detect default properties file for test")
+ assertThatIllegalStateException()
+ .isThrownBy(() -> buildMergedTestPropertySources(EmptyPropertySources.class))
+ .withMessageStartingWith("Could not detect default properties file for test class")
+ .withMessageContaining("class path resource")
+ .withMessageContaining("does not exist")
.withMessageContaining("EmptyPropertySources.properties");
}
@Test
public void extendedEmptyAnnotation() {
- assertThatIllegalStateException().isThrownBy(() ->
- buildMergedTestPropertySources(ExtendedEmptyPropertySources.class))
+ assertThatIllegalStateException()
+ .isThrownBy(() -> buildMergedTestPropertySources(ExtendedEmptyPropertySources.class))
.withMessageStartingWith("Could not detect default properties file for test")
+ .withMessageContaining("class path resource")
+ .withMessageContaining("does not exist")
.withMessageContaining("ExtendedEmptyPropertySources.properties");
}
+ @Test
+ public void repeatedTestPropertySourcesWithConflictingInheritLocationsFlags() {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> buildMergedTestPropertySources(RepeatedPropertySourcesWithConflictingInheritLocationsFlags.class))
+ .withMessageContaining("must declare the same value for 'inheritLocations' as other directly present or meta-present @TestPropertySource annotations");
+ }
+
+ @Test
+ public void repeatedTestPropertySourcesWithConflictingInheritPropertiesFlags() {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> buildMergedTestPropertySources(RepeatedPropertySourcesWithConflictingInheritPropertiesFlags.class))
+ .withMessageContaining("must declare the same value for 'inheritProperties' as other directly present or meta-present @TestPropertySource annotations");
+ }
+
@Test
public void value() {
assertMergedTestPropertySources(ValuePropertySources.class, asArray("classpath:/value.xml"),
@@ -82,8 +99,8 @@ public class TestPropertySourceUtilsTests {
@Test
public void locationsAndValueAttributes() {
- assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
- buildMergedTestPropertySources(LocationsAndValuePropertySources.class));
+ assertThatExceptionOfType(AnnotationConfigurationException.class)
+ .isThrownBy(() -> buildMergedTestPropertySources(LocationsAndValuePropertySources.class));
}
@Test
@@ -126,30 +143,37 @@ public class TestPropertySourceUtilsTests {
@Test
public void addPropertiesFilesToEnvironmentWithNullContext() {
- assertThatIllegalArgumentException().isThrownBy(() ->
- addPropertiesFilesToEnvironment((ConfigurableApplicationContext) null, FOO_LOCATIONS))
- .withMessageContaining("must not be null");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> addPropertiesFilesToEnvironment((ConfigurableApplicationContext) null, FOO_LOCATIONS))
+ .withMessageContaining("'context' must not be null");
}
@Test
public void addPropertiesFilesToEnvironmentWithContextAndNullLocations() {
- assertThatIllegalArgumentException().isThrownBy(() ->
- addPropertiesFilesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null))
- .withMessageContaining("must not be null");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> addPropertiesFilesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null))
+ .withMessageContaining("'locations' must not be null");
}
@Test
public void addPropertiesFilesToEnvironmentWithNullEnvironment() {
- assertThatIllegalArgumentException().isThrownBy(() ->
- addPropertiesFilesToEnvironment((ConfigurableEnvironment) null, mock(ResourceLoader.class), FOO_LOCATIONS))
- .withMessageContaining("must not be null");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> addPropertiesFilesToEnvironment((ConfigurableEnvironment) null, mock(ResourceLoader.class), FOO_LOCATIONS))
+ .withMessageContaining("'environment' must not be null");
+ }
+
+ @Test
+ public void addPropertiesFilesToEnvironmentWithEnvironmentLocationsAndNullResourceLoader() {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> addPropertiesFilesToEnvironment(new MockEnvironment(), null, FOO_LOCATIONS))
+ .withMessageContaining("'resourceLoader' must not be null");
}
@Test
public void addPropertiesFilesToEnvironmentWithEnvironmentAndNullLocations() {
- assertThatIllegalArgumentException().isThrownBy(() ->
- addPropertiesFilesToEnvironment(new MockEnvironment(), mock(ResourceLoader.class), (String[]) null))
- .withMessageContaining("must not be null");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> addPropertiesFilesToEnvironment(new MockEnvironment(), mock(ResourceLoader.class), (String[]) null))
+ .withMessageContaining("'locations' must not be null");
}
@Test
@@ -172,43 +196,43 @@ public class TestPropertySourceUtilsTests {
@Test
public void addInlinedPropertiesToEnvironmentWithNullContext() {
- assertThatIllegalArgumentException().isThrownBy(() ->
- addInlinedPropertiesToEnvironment((ConfigurableApplicationContext) null, KEY_VALUE_PAIR))
- .withMessageContaining("context");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> addInlinedPropertiesToEnvironment((ConfigurableApplicationContext) null, KEY_VALUE_PAIR))
+ .withMessageContaining("'context' must not be null");
}
@Test
public void addInlinedPropertiesToEnvironmentWithContextAndNullInlinedProperties() {
- assertThatIllegalArgumentException().isThrownBy(() ->
- addInlinedPropertiesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null))
- .withMessageContaining("inlined");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> addInlinedPropertiesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null))
+ .withMessageContaining("'inlinedProperties' must not be null");
}
@Test
public void addInlinedPropertiesToEnvironmentWithNullEnvironment() {
- assertThatIllegalArgumentException().isThrownBy(() ->
- addInlinedPropertiesToEnvironment((ConfigurableEnvironment) null, KEY_VALUE_PAIR))
- .withMessageContaining("environment");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> addInlinedPropertiesToEnvironment((ConfigurableEnvironment) null, KEY_VALUE_PAIR))
+ .withMessageContaining("'environment' must not be null");
}
@Test
public void addInlinedPropertiesToEnvironmentWithEnvironmentAndNullInlinedProperties() {
- assertThatIllegalArgumentException().isThrownBy(() ->
- addInlinedPropertiesToEnvironment(new MockEnvironment(), (String[]) null))
- .withMessageContaining("inlined");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> addInlinedPropertiesToEnvironment(new MockEnvironment(), (String[]) null))
+ .withMessageContaining("'inlinedProperties' must not be null");
}
@Test
public void addInlinedPropertiesToEnvironmentWithMalformedUnicodeInValue() {
- assertThatIllegalStateException().isThrownBy(() ->
- addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("key = \\uZZZZ")))
+ assertThatIllegalStateException()
+ .isThrownBy(() -> addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("key = \\uZZZZ")))
.withMessageContaining("Failed to load test environment property");
}
@Test
public void addInlinedPropertiesToEnvironmentWithMultipleKeyValuePairsInSingleInlinedProperty() {
- assertThatIllegalStateException().isThrownBy(() ->
- addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("a=b\nx=y")))
+ assertThatIllegalStateException()
+ .isThrownBy(() -> addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("a=b\nx=y")))
.withMessageContaining("Failed to load exactly one test environment property");
}
@@ -226,9 +250,9 @@ public class TestPropertySourceUtilsTests {
@Test
public void convertInlinedPropertiesToMapWithNullInlinedProperties() {
- assertThatIllegalArgumentException().isThrownBy(() ->
- convertInlinedPropertiesToMap((String[]) null))
- .withMessageContaining("inlined");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> convertInlinedPropertiesToMap((String[]) null))
+ .withMessageContaining("'inlinedProperties' must not be null");
}
@@ -256,6 +280,16 @@ public class TestPropertySourceUtilsTests {
static class ExtendedEmptyPropertySources extends EmptyPropertySources {
}
+ @TestPropertySource(locations = "foo.properties", inheritLocations = false)
+ @TestPropertySource(locations = "bar.properties", inheritLocations = true)
+ static class RepeatedPropertySourcesWithConflictingInheritLocationsFlags {
+ }
+
+ @TestPropertySource(properties = "a = b", inheritProperties = false)
+ @TestPropertySource(properties = "x = y", inheritProperties = true)
+ static class RepeatedPropertySourcesWithConflictingInheritPropertiesFlags {
+ }
+
@TestPropertySource(locations = "/foo", value = "/bar")
static class LocationsAndValuePropertySources {
}
diff --git a/spring-test/src/test/resources/log4j2-test.xml b/spring-test/src/test/resources/log4j2-test.xml
index db28ecb3db6..3fb0b802d6a 100644
--- a/spring-test/src/test/resources/log4j2-test.xml
+++ b/spring-test/src/test/resources/log4j2-test.xml
@@ -25,6 +25,7 @@