Merge branch '2.7.x'

This commit is contained in:
Phillip Webb 2022-01-14 13:57:35 -08:00
commit cb97aff1e7
3 changed files with 88 additions and 19 deletions

View File

@ -18,12 +18,15 @@ package org.springframework.boot.test.context;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.ApplicationContextFactory;
import org.springframework.boot.DefaultPropertiesPropertySource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.web.SpringBootMockServletContext;
import org.springframework.boot.test.util.TestPropertyValues;
@ -32,14 +35,18 @@ import org.springframework.boot.web.reactive.context.GenericReactiveWebApplicati
import org.springframework.boot.web.servlet.support.ServletContextApplicationContextInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.SpringVersion;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.CommandLinePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
@ -53,6 +60,7 @@ import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.test.context.web.WebMergedContextConfiguration;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.GenericWebApplicationContext;
@ -81,6 +89,9 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
*/
public class SpringBootContextLoader extends AbstractContextLoader {
private static final String[] PRIORITY_PROPERTY_SOURCES = { "configurationProperties",
DefaultPropertiesPropertySource.NAME, CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME };
@Override
public ApplicationContext loadContext(MergedContextConfiguration config) throws Exception {
Class<?>[] configClasses = config.getClasses();
@ -111,23 +122,49 @@ public class SpringBootContextLoader extends AbstractContextLoader {
application.setWebApplicationType(WebApplicationType.NONE);
}
application.setInitializers(initializers);
ConfigurableEnvironment environment = getEnvironment();
setActiveProfiles(environment, config.getActiveProfiles());
boolean customEnvironent = ReflectionUtils.findMethod(getClass(), "getEnvironment")
.getDeclaringClass() != SpringBootContextLoader.class;
if (customEnvironent) {
ConfigurableEnvironment environment = getEnvironment();
prepareEnvironment(config, application, environment, false);
application.setEnvironment(environment);
}
else {
application.addListeners(new PrepareEnvironmentListener(config));
}
String[] args = SpringBootTestArgs.get(config.getContextCustomizers());
return application.run(args);
}
private void prepareEnvironment(MergedContextConfiguration config, SpringApplication application,
ConfigurableEnvironment environment, boolean applicationEnvironment) {
MutablePropertySources propertySources = environment.getPropertySources();
List<PropertySource<?>> priorityPropertySources = new ArrayList<>();
if (applicationEnvironment) {
for (String priorityPropertySourceName : PRIORITY_PROPERTY_SOURCES) {
PropertySource<?> priorityPropertySource = propertySources.get(priorityPropertySourceName);
if (priorityPropertySource != null) {
priorityPropertySources.add(priorityPropertySource);
propertySources.remove(priorityPropertySourceName);
}
}
}
setActiveProfiles(environment, config.getActiveProfiles(), applicationEnvironment);
ResourceLoader resourceLoader = (application.getResourceLoader() != null) ? application.getResourceLoader()
: new DefaultResourceLoader(null);
TestPropertySourceUtils.addPropertiesFilesToEnvironment(environment, resourceLoader,
config.getPropertySourceLocations());
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, getInlinedProperties(config));
application.setEnvironment(environment);
String[] args = SpringBootTestArgs.get(config.getContextCustomizers());
return application.run(args);
Collections.reverse(priorityPropertySources);
priorityPropertySources.forEach(propertySources::addFirst);
}
private void setActiveProfiles(ConfigurableEnvironment environment, String[] profiles) {
private void setActiveProfiles(ConfigurableEnvironment environment, String[] profiles,
boolean applicationEnvironment) {
if (ObjectUtils.isEmpty(profiles)) {
return;
}
if (!(environment instanceof TestEnvironment)) {
if (!applicationEnvironment) {
environment.setActiveProfiles(profiles);
}
String[] pairs = new String[profiles.length];
@ -152,7 +189,7 @@ public class SpringBootContextLoader extends AbstractContextLoader {
* @return a {@link ConfigurableEnvironment} instance
*/
protected ConfigurableEnvironment getEnvironment() {
return new TestEnvironment();
return new StandardEnvironment();
}
protected String[] getInlinedProperties(MergedContextConfiguration config) {
@ -304,19 +341,25 @@ public class SpringBootContextLoader extends AbstractContextLoader {
}
/**
* Side-effect free {@link Environment} that doesn't set profiles directly from
* properties.
* {@link ApplicationListener} used to prepare the application created environment.
*/
static class TestEnvironment extends StandardEnvironment {
private class PrepareEnvironmentListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, PriorityOrdered {
@Override
protected String doGetActiveProfilesProperty() {
return null;
private final MergedContextConfiguration config;
PrepareEnvironmentListener(MergedContextConfiguration config) {
this.config = config;
}
@Override
protected String doGetDefaultProfilesProperty() {
return null;
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
prepareEnvironment(this.config, event.getSpringApplication(), event.getEnvironment(), true);
}
}

View File

@ -16,7 +16,9 @@
package org.springframework.boot.test.context;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@ -24,11 +26,14 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestContextManager;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.test.util.ReflectionTestUtils;
@ -127,6 +132,20 @@ class SpringBootContextLoaderTests {
assertThat(environment.getPropertySources().get("active-test-profiles")).isNotNull();
}
@Test
void propertySourceOrdering() throws Exception {
TestContext context = new ExposedTestContextManager(PropertySourceOrdering.class).getExposedTestContext();
ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getApplicationContext()
.getEnvironment();
List<String> names = environment.getPropertySources().stream().map(PropertySource::getName)
.collect(Collectors.toList());
String last = names.remove(names.size() - 1);
assertThat(names).containsExactly("configurationProperties", "commandLineArgs", "Inlined Test Properties",
"servletConfigInitParams", "servletContextInitParams", "systemProperties", "systemEnvironment",
"random");
assertThat(last).startsWith("Config resource");
}
private String[] getActiveProfiles(Class<?> testClass) {
TestContext testContext = new ExposedTestContextManager(testClass).getExposedTestContext();
ApplicationContext applicationContext = testContext.getApplicationContext();
@ -198,6 +217,12 @@ class SpringBootContextLoaderTests {
}
@SpringBootTest(classes = Config.class, args = "args", properties = "one=1")
@TestPropertySource(properties = "two=2")
static class PropertySourceOrdering {
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.test.context.ActiveProfiles;
@ -32,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Madhura Bhave
*/
@SpringBootTest(properties = "enableEnvironmentPostProcessor=true") // gh-28530
@SpringBootTest(webEnvironment = WebEnvironment.NONE, properties = "enableEnvironmentPostProcessor=true") // gh-28530
@ActiveProfiles("hello")
class ActiveProfilesTests {