Rework @TestPropertySource compatibility
Rework @TestPropertySource changes introduced in commit d251b513
to restore compatibility with Spring Boot 1.1
- Only add the `server.port` property when no @IntegrationTest
annotation is found.
- Always add a default `spring.jmx.enabled=false` property.
- Restore the SpringApplicationContextLoader.getEnvironmentProperties
protected method.
- Remove the @IntegrationTest.properties attribute.
See gh-1697
This commit is contained in:
parent
2e7aa4685b
commit
24f95b975d
|
@ -25,7 +25,6 @@ import java.lang.annotation.Target;
|
|||
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
|
||||
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
|
||||
|
@ -42,21 +41,16 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi
|
|||
@Target(ElementType.TYPE)
|
||||
// Leave out the ServletTestExecutionListener because it only deals with Mock* servlet
|
||||
// stuff. A real embedded application will not need the mocks.
|
||||
@TestExecutionListeners(listeners = { IntegrationTestPropertiesListener.class, DependencyInjectionTestExecutionListener.class,
|
||||
@TestExecutionListeners(listeners = { IntegrationTestPropertiesListener.class,
|
||||
DependencyInjectionTestExecutionListener.class,
|
||||
DirtiesContextTestExecutionListener.class,
|
||||
TransactionalTestExecutionListener.class })
|
||||
@TestPropertySource
|
||||
public @interface IntegrationTest {
|
||||
|
||||
/**
|
||||
* Synonym for properties().
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Properties in form {@literal key=value} that should be added to the Spring
|
||||
* {@link Environment} before the test runs.
|
||||
*/
|
||||
String[] properties() default {"server.port=-1", "spring.jmx.enabled=false"};
|
||||
String[] value() default {};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,96 +19,59 @@ import java.util.Arrays;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Manipulate the TestContext to merge properties from <code>@IntegrationTest</code> value
|
||||
* and properties attributes.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* Manipulate the TestContext to merge properties from {@code @IntegrationTest}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class IntegrationTestPropertiesListener extends AbstractTestExecutionListener {
|
||||
class IntegrationTestPropertiesListener extends AbstractTestExecutionListener {
|
||||
|
||||
private String[] defaultValues = (String[]) AnnotationUtils.getDefaultValue(
|
||||
IntegrationTest.class, "properties");
|
||||
private static final String ANNOTATION_TYPE = IntegrationTest.class.getName();
|
||||
|
||||
@Override
|
||||
public void prepareTestInstance(TestContext testContext) throws Exception {
|
||||
MergedContextConfiguration config = null;
|
||||
Class<?> testClass = testContext.getTestClass();
|
||||
if (AnnotatedElementUtils.isAnnotated(testClass, ANNOTATION_TYPE)) {
|
||||
AnnotationAttributes annotationAttributes = AnnotatedElementUtils
|
||||
.getAnnotationAttributes(testClass, ANNOTATION_TYPE);
|
||||
addPropertySourceProperties(testContext,
|
||||
annotationAttributes.getStringArray("value"));
|
||||
}
|
||||
}
|
||||
|
||||
private void addPropertySourceProperties(TestContext testContext, String[] properties) {
|
||||
try {
|
||||
// Here be hacks...
|
||||
config = (MergedContextConfiguration) ReflectionTestUtils.getField(
|
||||
testContext, "mergedContextConfiguration");
|
||||
ReflectionTestUtils.setField(config, "propertySourceProperties",
|
||||
getEnvironmentProperties(config));
|
||||
addPropertySourcePropertiesUsingReflection(testContext, properties);
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
throw e;
|
||||
catch (RuntimeException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected String[] getEnvironmentProperties(MergedContextConfiguration config) {
|
||||
IntegrationTest annotation = AnnotationUtils.findAnnotation(
|
||||
config.getTestClass(), IntegrationTest.class);
|
||||
return mergeProperties(
|
||||
getDefaultEnvironmentProperties(config.getPropertySourceProperties(),
|
||||
annotation), getEnvironmentProperties(annotation));
|
||||
}
|
||||
|
||||
private String[] getDefaultEnvironmentProperties(String[] original,
|
||||
IntegrationTest annotation) {
|
||||
String[] defaults = mergeProperties(original, defaultValues);
|
||||
if (annotation == null || defaults.length == 0) {
|
||||
// Without an @IntegrationTest we can assume the defaults are fine
|
||||
return defaults;
|
||||
private void addPropertySourcePropertiesUsingReflection(TestContext testContext,
|
||||
String[] properties) throws Exception {
|
||||
if (properties.length == 0) {
|
||||
return;
|
||||
}
|
||||
// If @IntegrationTest is present we don't provide a default for the server.port
|
||||
return filterPorts((String[]) AnnotationUtils.getDefaultValue(annotation,
|
||||
"properties"));
|
||||
}
|
||||
|
||||
private String[] filterPorts(String[] values) {
|
||||
|
||||
Set<String> result = new LinkedHashSet<String>();
|
||||
for (String value : values) {
|
||||
if (!value.contains(".port")) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
return result.toArray(new String[0]);
|
||||
|
||||
}
|
||||
|
||||
private String[] getEnvironmentProperties(IntegrationTest annotation) {
|
||||
if (annotation == null) {
|
||||
return new String[0];
|
||||
}
|
||||
if (Arrays.asList(annotation.properties()).equals(Arrays.asList(defaultValues))) {
|
||||
return annotation.value();
|
||||
}
|
||||
if (annotation.value().length == 0) {
|
||||
return annotation.properties();
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Either properties or value can be provided but not both");
|
||||
}
|
||||
|
||||
private String[] mergeProperties(String[] original, String[] extra) {
|
||||
Set<String> result = new LinkedHashSet<String>();
|
||||
for (String value : original) {
|
||||
result.add(value);
|
||||
}
|
||||
for (String value : extra) {
|
||||
result.add(value);
|
||||
}
|
||||
return result.toArray(new String[0]);
|
||||
MergedContextConfiguration configuration = (MergedContextConfiguration) ReflectionTestUtils
|
||||
.getField(testContext, "mergedContextConfiguration");
|
||||
Set<String> merged = new LinkedHashSet<String>((Arrays.asList(configuration
|
||||
.getPropertySourceProperties())));
|
||||
merged.addAll(Arrays.asList(properties));
|
||||
ReflectionTestUtils.setField(configuration, "propertySourceProperties",
|
||||
merged.toArray(new String[merged.size()]));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@ import java.io.IOException;
|
|||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -90,7 +91,7 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
|||
.addAfter(
|
||||
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
|
||||
new MapPropertySource("integrationTest",
|
||||
extractEnvironmentProperties(config.getPropertySourceProperties())));
|
||||
getEnvironmentProperties(config)));
|
||||
application.setEnvironment(environment);
|
||||
List<ApplicationContextInitializer<?>> initializers = getInitializers(config,
|
||||
application);
|
||||
|
@ -101,36 +102,9 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
|||
application.setWebEnvironment(false);
|
||||
}
|
||||
application.setInitializers(initializers);
|
||||
|
||||
return application.run();
|
||||
}
|
||||
|
||||
// Instead of parsing the keys ourselves, we rely on standard handling
|
||||
protected Map<String, Object> extractEnvironmentProperties(String[] values) {
|
||||
Map<String, Object> properties = new HashMap<String, Object>();
|
||||
if (values==null) {
|
||||
return properties;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String value : values) {
|
||||
sb.append(value).append(LINE_SEPARATOR);
|
||||
}
|
||||
String content = sb.toString();
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(new StringReader(content));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException("Unexpected could not load properties from '"
|
||||
+ content + "'", e);
|
||||
}
|
||||
|
||||
for (String name : props.stringPropertyNames()) {
|
||||
properties.put(name, props.getProperty(name));
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processContextConfiguration(
|
||||
ContextConfigurationAttributes configAttributes) {
|
||||
|
@ -176,8 +150,52 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
|||
return AnnotationConfigContextLoaderUtils
|
||||
.detectDefaultConfigurationClasses(declaringClass);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected Map<String, Object> getEnvironmentProperties(
|
||||
MergedContextConfiguration config) {
|
||||
Map<String, Object> properties = new LinkedHashMap<String, Object>();
|
||||
// JMX bean names will clash if the same bean is used in multiple contexts
|
||||
disableJmx(properties);
|
||||
properties.putAll(extractEnvironmentProperties(config
|
||||
.getPropertySourceProperties()));
|
||||
if (AnnotationUtils.findAnnotation(config.getTestClass(), IntegrationTest.class) == null) {
|
||||
properties.putAll(getDefaultEnvironmentProperties());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void disableJmx(Map<String, Object> properties) {
|
||||
properties.put("spring.jmx.enabled", "false");
|
||||
}
|
||||
|
||||
private Map<String, String> getDefaultEnvironmentProperties() {
|
||||
return Collections.singletonMap("server.port", "-1");
|
||||
}
|
||||
|
||||
Map<String, Object> extractEnvironmentProperties(String[] values) {
|
||||
// Instead of parsing the keys ourselves, we rely on standard handling
|
||||
if (values == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
String content = StringUtils.arrayToDelimitedString(values, LINE_SEPARATOR);
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
properties.load(new StringReader(content));
|
||||
return asMap(properties);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Unexpected could not load properties from '"
|
||||
+ content + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> asMap(Properties properties) {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
for (String name : properties.stringPropertyNames()) {
|
||||
map.put(name, properties.getProperty(name));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private List<ApplicationContextInitializer<?>> getInitializers(
|
||||
MergedContextConfiguration mergedConfig, SpringApplication application) {
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.boot.test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
@ -27,6 +25,8 @@ import org.springframework.context.annotation.Configuration;
|
|||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* Tests for disabling JMX by default
|
||||
*
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
|
||||
package org.springframework.boot.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
@ -27,6 +24,9 @@ import org.springframework.test.context.TestContext;
|
|||
import org.springframework.test.context.TestContextManager;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringApplicationContextLoader}
|
||||
*
|
||||
|
@ -43,24 +43,12 @@ public class SpringApplicationContextLoaderTests {
|
|||
assertKey(config, "anotherKey", "anotherValue");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void environmentPropertiesDefaults() throws Exception {
|
||||
Map<String, Object> config = getEnvironmentProperties(SimpleConfig.class);
|
||||
assertMissingKey(config, "server.port");
|
||||
assertKey(config, "spring.jmx.enabled", "false");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void environmentPropertiesOverrideDefaults() throws Exception {
|
||||
Map<String, Object> config = getEnvironmentProperties(OverrideConfig.class);
|
||||
assertKey(config, "server.port", "2345");
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void environmentPropertiesIllegal() throws Exception {
|
||||
getEnvironmentProperties(IllegalConfig.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void environmentPropertiesAppend() throws Exception {
|
||||
Map<String, Object> config = getEnvironmentProperties(AppendConfig.class);
|
||||
|
@ -82,12 +70,15 @@ public class SpringApplicationContextLoaderTests {
|
|||
assertKey(config, "anotherKey", "another=Value");
|
||||
}
|
||||
|
||||
private Map<String, Object> getEnvironmentProperties(Class<?> testClass) throws Exception {
|
||||
TestContext context = new ExposedTestContextManager(testClass).getExposedTestContext();
|
||||
private Map<String, Object> getEnvironmentProperties(Class<?> testClass)
|
||||
throws Exception {
|
||||
TestContext context = new ExposedTestContextManager(testClass)
|
||||
.getExposedTestContext();
|
||||
new IntegrationTestPropertiesListener().prepareTestInstance(context);
|
||||
MergedContextConfiguration config = (MergedContextConfiguration) ReflectionTestUtils.getField(
|
||||
context, "mergedContextConfiguration");
|
||||
return this.loader.extractEnvironmentProperties(config.getPropertySourceProperties());
|
||||
MergedContextConfiguration config = (MergedContextConfiguration) ReflectionTestUtils
|
||||
.getField(context, "mergedContextConfiguration");
|
||||
return this.loader.extractEnvironmentProperties(config
|
||||
.getPropertySourceProperties());
|
||||
}
|
||||
|
||||
private void assertKey(Map<String, Object> actual, String key, Object value) {
|
||||
|
@ -95,10 +86,6 @@ public class SpringApplicationContextLoaderTests {
|
|||
assertEquals(value, actual.get(key));
|
||||
}
|
||||
|
||||
private void assertMissingKey(Map<String, Object> actual, String key) {
|
||||
assertTrue("Key '" + key + "' found", !actual.containsKey(key));
|
||||
}
|
||||
|
||||
@IntegrationTest({ "key=myValue", "anotherKey:anotherValue" })
|
||||
static class SimpleConfig {
|
||||
}
|
||||
|
@ -107,11 +94,7 @@ public class SpringApplicationContextLoaderTests {
|
|||
static class OverrideConfig {
|
||||
}
|
||||
|
||||
@IntegrationTest(value = { "key=aValue", "anotherKey:anotherValue" }, properties = { "key=myValue", "otherKey=otherValue" })
|
||||
static class IllegalConfig {
|
||||
}
|
||||
|
||||
@IntegrationTest(properties = { "key=myValue", "otherKey=otherValue" })
|
||||
@IntegrationTest({ "key=myValue", "otherKey=otherValue" })
|
||||
static class AppendConfig {
|
||||
}
|
||||
|
||||
|
@ -122,18 +105,20 @@ public class SpringApplicationContextLoaderTests {
|
|||
@IntegrationTest({ "key=my:Value", "anotherKey:another=Value" })
|
||||
static class AnotherSeparatorInValue {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link TestContextManager} which exposes the {@link TestContext}.
|
||||
*/
|
||||
private static class ExposedTestContextManager extends TestContextManager {
|
||||
|
||||
public ExposedTestContextManager(Class<?> testClass) {
|
||||
super(testClass);
|
||||
}
|
||||
|
||||
|
||||
public final TestContext getExposedTestContext() {
|
||||
return super.getTestContext();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue