/* * 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.context.config; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.LoggerConfig; import org.assertj.core.api.Condition; import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.testutil.InternalOutputCapture; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.PropertySource; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.SimpleCommandLinePropertySource; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; /** * Tests for {@link ConfigFileApplicationListener}. * * @author Phillip Webb * @author Dave Syer * @author EddĂș MelĂ©ndez */ public class ConfigFileApplicationListenerTests { private final StandardEnvironment environment = new StandardEnvironment(); private final SpringApplication application = new SpringApplication(); private final ConfigFileApplicationListener initializer = new ConfigFileApplicationListener(); @Rule public ExpectedException expected = ExpectedException.none(); @Rule public InternalOutputCapture out = new InternalOutputCapture(); private ConfigurableApplicationContext context; @After public void cleanUp() { if (this.context != null) { this.context.close(); } System.clearProperty("the.property"); System.clearProperty("spring.config.location"); } @Test public void loadCustomResource() throws Exception { this.application.setResourceLoader(new ResourceLoader() { @Override public Resource getResource(final String location) { if (location.equals("classpath:/custom.properties")) { return new ByteArrayResource("the.property: fromcustom".getBytes(), location) { @Override public String getFilename() { return location; } }; } return null; } @Override public ClassLoader getClassLoader() { return getClass().getClassLoader(); } }); this.initializer.setSearchNames("custom"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("fromcustom"); } @Test public void loadPropertiesFile() throws Exception { this.initializer.setSearchNames("testproperties"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("frompropertiesfile"); } @Test public void loadDefaultPropertiesFile() throws Exception { this.environment.setDefaultProfiles("thedefault"); this.initializer.setSearchNames("testprofiles"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("fromdefaultpropertiesfile"); } @Test public void loadTwoPropertiesFile() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.location=" + "classpath:application.properties,classpath:testproperties.properties"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("frompropertiesfile"); } @Test public void loadTwoPropertiesFilesWithProfiles() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.location=" + "classpath:enableprofile.properties,classpath:enableother.properties"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).containsExactly("other"); String property = this.environment.getProperty("my.property"); assertThat(property).isEqualTo("fromotherpropertiesfile"); } @Test public void loadTwoPropertiesFilesWithProfilesAndSwitchOneOff() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.location=classpath:enabletwoprofiles.properties," + "classpath:enableprofile.properties"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).containsExactly("myprofile"); String property = this.environment.getProperty("the.property"); // The value from the second file wins (no profile-specific configuration is // actually loaded) assertThat(property).isEqualTo("frompropertiesfile"); } @Test public void loadTwoPropertiesFilesWithProfilesAndSwitchOneOffFromSpecificLocation() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.name=enabletwoprofiles", "spring.config.location=classpath:enableprofile.properties"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).containsExactly("myprofile"); String property = this.environment.getProperty("the.property"); // The value from the second file wins (no profile-specific configuration is // actually loaded) assertThat(property).isEqualTo("frompropertiesfile"); } @Test public void localFileTakesPrecedenceOverClasspath() throws Exception { File localFile = new File(new File("."), "application.properties"); assertThat(localFile.exists()).isFalse(); try { Properties properties = new Properties(); properties.put("the.property", "fromlocalfile"); OutputStream out = new FileOutputStream(localFile); try { properties.store(out, ""); } finally { out.close(); } this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("fromlocalfile"); } finally { localFile.delete(); } } @Test public void moreSpecificLocationTakesPrecedenceOverRoot() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.name=specific"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); assertThat(property).isEqualTo("specific"); } @Test public void loadTwoOfThreePropertiesFile() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.location=classpath:application.properties," + "classpath:testproperties.properties," + "classpath:nonexistent.properties"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("frompropertiesfile"); } @Test public void randomValue() throws Exception { this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("random.value"); assertThat(property).isNotNull(); } @Test public void loadTwoPropertiesFiles() throws Exception { this.initializer.setSearchNames("moreproperties,testproperties"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); // The search order has highest precedence last (like merging a map) assertThat(property).isEqualTo("frompropertiesfile"); } @Test public void loadYamlFile() throws Exception { this.initializer.setSearchNames("testyaml"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); assertThat(property).isEqualTo("fromyamlfile"); assertThat(this.environment.getProperty("my.array[0]")).isEqualTo("1"); assertThat(this.environment.getProperty("my.array")).isNull(); } @Test public void loadProfileEmptySameAsNotSpecified() throws Exception { this.initializer.setSearchNames("testprofilesempty"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); assertThat(property).isEqualTo("fromemptyprofile"); } @Test public void loadDefaultYamlDocument() throws Exception { this.environment.setDefaultProfiles("thedefault"); this.initializer.setSearchNames("testprofilesdocument"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); assertThat(property).isEqualTo("fromdefaultprofile"); } @Test public void loadDefaultYamlDocumentNotActivated() throws Exception { this.environment.setDefaultProfiles("thedefault"); this.environment.setActiveProfiles("other"); this.initializer.setSearchNames("testprofilesdocument"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); assertThat(property).isEqualTo("fromotherprofile"); } @Test public void commandLineWins() throws Exception { this.environment.getPropertySources().addFirst( new SimpleCommandLinePropertySource("--the.property=fromcommandline")); this.initializer.setSearchNames("testproperties"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("fromcommandline"); } @Test public void systemPropertyWins() throws Exception { System.setProperty("the.property", "fromsystem"); this.initializer.setSearchNames("testproperties"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("fromsystem"); } @Test public void defaultPropertyAsFallback() throws Exception { this.environment.getPropertySources() .addLast(new MapPropertySource("defaultProperties", Collections.singletonMap("my.fallback", (Object) "foo"))); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.fallback"); assertThat(property).isEqualTo("foo"); } @Test public void defaultPropertyAsFallbackDuringFileParsing() throws Exception { this.environment.getPropertySources() .addLast(new MapPropertySource("defaultProperties", Collections .singletonMap("spring.config.name", (Object) "testproperties"))); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("frompropertiesfile"); } @Test public void loadPropertiesThenProfilePropertiesActivatedInSpringApplication() throws Exception { // This should be the effect of calling // SpringApplication.setAdditionalProfiles("other") this.environment.setActiveProfiles("other"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); // The "other" profile is activated in SpringApplication so it should take // precedence over the default profile assertThat(property).isEqualTo("fromotherpropertiesfile"); } @Test public void twoProfilesFromProperties() throws Exception { // This should be the effect of calling // SpringApplication.setAdditionalProfiles("other", "dev") this.environment.setActiveProfiles("other", "dev"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); // The "dev" profile is activated in SpringApplication so it should take // precedence over the default profile assertThat(property).isEqualTo("fromdevpropertiesfile"); } @Test public void loadPropertiesThenProfilePropertiesActivatedInFirst() throws Exception { this.initializer.setSearchNames("enableprofile"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); // The "myprofile" profile is activated in enableprofile.properties so its value // should show up here assertThat(property).isEqualTo("fromprofilepropertiesfile"); } @Test public void loadPropertiesThenProfilePropertiesWithOverride() throws Exception { this.environment.setActiveProfiles("other"); this.initializer.setSearchNames("enableprofile"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("other.property"); // The "other" profile is activated before any processing starts assertThat(property).isEqualTo("fromotherpropertiesfile"); property = this.environment.getProperty("the.property"); // The "myprofile" profile is activated in enableprofile.properties and "other" // was not activated by setting spring.profiles.active so "myprofile" should still // be activated assertThat(property).isEqualTo("fromprofilepropertiesfile"); } @Test public void profilePropertiesUsedInPlaceholders() throws Exception { this.initializer.setSearchNames("enableprofile"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("one.more"); assertThat(property).isEqualTo("fromprofilepropertiesfile"); } @Test public void profilesAddedToEnvironmentAndViaProperty() throws Exception { // External profile takes precedence over profile added via the environment TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.profiles.active=other"); this.environment.addActiveProfile("dev"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).contains("dev", "other"); assertThat(this.environment.getProperty("my.property")) .isEqualTo("fromotherpropertiesfile"); validateProfilePrecedence(null, "dev", "other"); } @Test public void profilesAddedToEnvironmentAndViaPropertyDuplicate() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.profiles.active=dev,other"); this.environment.addActiveProfile("dev"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).contains("dev", "other"); assertThat(this.environment.getProperty("my.property")) .isEqualTo("fromotherpropertiesfile"); validateProfilePrecedence(null, "dev", "other"); } @Test public void profilesAddedToEnvironmentAndViaPropertyDuplicateEnvironmentWins() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.profiles.active=other,dev"); this.environment.addActiveProfile("other"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).contains("dev", "other"); assertThat(this.environment.getProperty("my.property")) .isEqualTo("fromdevpropertiesfile"); validateProfilePrecedence(null, "other", "dev"); } @Test public void postProcessorsAreOrderedCorrectly() { TestConfigFileApplicationListener testListener = new TestConfigFileApplicationListener(); testListener.onApplicationEvent(new ApplicationEnvironmentPreparedEvent( this.application, new String[0], this.environment)); } private void validateProfilePrecedence(String... profiles) { ApplicationPreparedEvent event = new ApplicationPreparedEvent( new SpringApplication(), new String[0], new AnnotationConfigApplicationContext()); withDebugLogging(() -> { this.initializer.onApplicationEvent(event); }); String log = this.out.toString(); // First make sure that each profile got processed only once for (String profile : profiles) { String reason = "Wrong number of occurrences for profile '" + profile + "' --> " + log; assertThat(StringUtils.countOccurrencesOf(log, createLogForProfile(profile))) .as(reason).isEqualTo(1); } // Make sure the order of loading is the right one for (String profile : profiles) { String line = createLogForProfile(profile); int index = log.indexOf(line); assertThat(index) .as("Loading profile '" + profile + "' not found in '" + log + "'") .isNotEqualTo(-1); log = log.substring(index + line.length()); } } private void withDebugLogging(Runnable runnable) { LoggerContext loggingContext = (LoggerContext) LogManager.getContext(false); org.apache.logging.log4j.core.config.Configuration configuration = loggingContext .getConfiguration(); configuration.addLogger(ConfigFileApplicationListener.class.getName(), new LoggerConfig(ConfigFileApplicationListener.class.getName(), Level.DEBUG, true)); loggingContext.updateLoggers(); try { runnable.run(); } finally { configuration.removeLogger(ConfigFileApplicationListener.class.getName()); loggingContext.updateLoggers(); } } private String createLogForProfile(String profile) { String suffix = profile != null ? "-" + profile : ""; String string = ".properties)"; return "Loaded config file '" + new File("target/test-classes/application" + suffix + ".properties") .getAbsoluteFile().toURI().toString() + "' (classpath:/application" + suffix + string; } @Test public void yamlProfiles() throws Exception { this.initializer.setSearchNames("testprofiles"); this.environment.setActiveProfiles("dev"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); assertThat(property).isEqualTo("fromdevprofile"); property = this.environment.getProperty("my.other"); assertThat(property).isEqualTo("notempty"); } @Test public void yamlTwoProfiles() throws Exception { this.initializer.setSearchNames("testprofiles"); this.environment.setActiveProfiles("other", "dev"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); assertThat(property).isEqualTo("fromdevprofile"); property = this.environment.getProperty("my.other"); assertThat(property).isEqualTo("notempty"); } @Test public void yamlSetsProfiles() throws Exception { this.initializer.setSearchNames("testsetprofiles"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).containsExactly("dev"); String property = this.environment.getProperty("my.property"); assertThat(this.environment.getActiveProfiles()).contains("dev"); assertThat(property).isEqualTo("fromdevprofile"); List<String> names = StreamSupport .stream(this.environment.getPropertySources().spliterator(), false) .map(org.springframework.core.env.PropertySource::getName) .collect(Collectors.toList()); assertThat(names).contains( "applicationConfig: [classpath:/testsetprofiles.yml]#dev", "applicationConfig: [classpath:/testsetprofiles.yml]"); } @Test public void yamlSetsMultiProfiles() throws Exception { this.initializer.setSearchNames("testsetmultiprofiles"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).containsExactly("dev", "healthcheck"); } @Test public void yamlSetsMultiProfilesWhenListProvided() throws Exception { this.initializer.setSearchNames("testsetmultiprofileslist"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).containsExactly("dev", "healthcheck"); } @Test public void yamlSetsMultiProfilesWithWhitespace() throws Exception { this.initializer.setSearchNames("testsetmultiprofileswhitespace"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).containsExactly("dev", "healthcheck"); } @Test public void yamlProfileCanBeChanged() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.profiles.active=prod"); this.initializer.setSearchNames("testsetprofiles"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()).containsExactly("prod"); } @Test public void specificNameAndProfileFromExistingSource() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.profiles.active=specificprofile", "spring.config.name=specificfile"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("my.property"); assertThat(property).isEqualTo("fromspecificpropertiesfile"); } @Test public void specificResource() throws Exception { String location = "classpath:specificlocation.properties"; TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.location=" + location); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("fromspecificlocation"); assertThat(this.environment).has(matchingPropertySource( "applicationConfig: " + "[classpath:specificlocation.properties]")); // The default property source is still there assertThat(this.environment).has(matchingPropertySource( "applicationConfig: " + "[classpath:/application.properties]")); assertThat(this.environment.getProperty("foo")).isEqualTo("bucket"); } @Test public void specificResourceAsFile() throws Exception { String location = "file:src/test/resources/specificlocation.properties"; TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.location=" + location); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment) .has(matchingPropertySource("applicationConfig: [" + location + "]")); } @Test public void specificResourceDefaultsToFile() throws Exception { String location = "src/test/resources/specificlocation.properties"; TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.location=" + location); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment).has( matchingPropertySource("applicationConfig: [file:" + location + "]")); } @Test public void absoluteResourceDefaultsToFile() throws Exception { String location = new File("src/test/resources/specificlocation.properties") .getAbsolutePath().replace("\\", "/"); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.config.location=" + location); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment) .has(matchingPropertySource("applicationConfig: [file:" + location.replace(File.separatorChar, '/') + "]")); } @Test public void propertySourceAnnotation() throws Exception { SpringApplication application = new SpringApplication(WithPropertySource.class); application.setWebApplicationType(WebApplicationType.NONE); ConfigurableApplicationContext context = application.run(); String property = context.getEnvironment().getProperty("the.property"); assertThat(property).isEqualTo("fromspecificlocation"); property = context.getEnvironment().getProperty("my.property"); assertThat(property).isEqualTo("fromapplicationproperties"); assertThat(context.getEnvironment()).has(matchingPropertySource( "class path resource " + "[specificlocation.properties]")); context.close(); } @Test public void propertySourceAnnotationWithPlaceholder() throws Exception { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "source.location=specificlocation"); SpringApplication application = new SpringApplication( WithPropertySourcePlaceholders.class); application.setEnvironment(this.environment); application.setWebApplicationType(WebApplicationType.NONE); ConfigurableApplicationContext context = application.run(); String property = context.getEnvironment().getProperty("the.property"); assertThat(property).isEqualTo("fromspecificlocation"); assertThat(context.getEnvironment()).has(matchingPropertySource( "class path resource " + "[specificlocation.properties]")); context.close(); } @Test public void propertySourceAnnotationWithName() throws Exception { SpringApplication application = new SpringApplication( WithPropertySourceAndName.class); application.setWebApplicationType(WebApplicationType.NONE); ConfigurableApplicationContext context = application.run(); String property = context.getEnvironment().getProperty("the.property"); assertThat(property).isEqualTo("fromspecificlocation"); assertThat(context.getEnvironment()).has(matchingPropertySource("foo")); context.close(); } @Test public void propertySourceAnnotationInProfile() throws Exception { SpringApplication application = new SpringApplication( WithPropertySourceInProfile.class); application.setWebApplicationType(WebApplicationType.NONE); ConfigurableApplicationContext context = application .run("--spring.profiles.active=myprofile"); String property = context.getEnvironment().getProperty("the.property"); assertThat(property).isEqualTo("frompropertiesfile"); assertThat(context.getEnvironment()).has(matchingPropertySource( "class path resource " + "[enableprofile.properties]")); assertThat(context.getEnvironment()).doesNotHave(matchingPropertySource( "classpath:/" + "enableprofile-myprofile.properties")); context.close(); } @Test public void propertySourceAnnotationAndNonActiveProfile() throws Exception { SpringApplication application = new SpringApplication( WithPropertySourceAndProfile.class); application.setWebApplicationType(WebApplicationType.NONE); ConfigurableApplicationContext context = application.run(); String property = context.getEnvironment().getProperty("my.property"); assertThat(property).isEqualTo("fromapplicationproperties"); assertThat(context.getEnvironment()).doesNotHave(matchingPropertySource( "classpath:" + "/enableprofile-myprofile.properties")); context.close(); } @Test public void propertySourceAnnotationMultipleLocations() throws Exception { SpringApplication application = new SpringApplication( WithPropertySourceMultipleLocations.class); application.setWebApplicationType(WebApplicationType.NONE); ConfigurableApplicationContext context = application.run(); String property = context.getEnvironment().getProperty("the.property"); assertThat(property).isEqualTo("frommorepropertiesfile"); assertThat(context.getEnvironment()).has(matchingPropertySource( "class path resource " + "[specificlocation.properties]")); context.close(); } @Test public void propertySourceAnnotationMultipleLocationsAndName() throws Exception { SpringApplication application = new SpringApplication( WithPropertySourceMultipleLocationsAndName.class); application.setWebApplicationType(WebApplicationType.NONE); ConfigurableApplicationContext context = application.run(); String property = context.getEnvironment().getProperty("the.property"); assertThat(property).isEqualTo("frommorepropertiesfile"); assertThat(context.getEnvironment()).has(matchingPropertySource("foo")); context.close(); } @Test public void activateProfileFromProfileSpecificProperties() throws Exception { SpringApplication application = new SpringApplication(Config.class); application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run("--spring.profiles.active=includeprofile"); ConfigurableEnvironment environment = this.context.getEnvironment(); assertThat(environment).has(matchingProfile("includeprofile")); assertThat(environment).has(matchingProfile("specific")); assertThat(environment).has(matchingProfile("morespecific")); assertThat(environment).has(matchingProfile("yetmorespecific")); assertThat(environment).doesNotHave(matchingProfile("missing")); } @Test public void profileSubDocumentInSameProfileSpecificFile() throws Exception { // gh-340 SpringApplication application = new SpringApplication(Config.class); application.setWebApplicationType(WebApplicationType.NONE); this.context = application .run("--spring.profiles.active=activeprofilewithsubdoc"); String property = this.context.getEnvironment().getProperty("foobar"); assertThat(property).isEqualTo("baz"); } @Test public void profileSubDocumentInDifferentProfileSpecificFile() throws Exception { // gh-4132 SpringApplication application = new SpringApplication(Config.class); application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run( "--spring.profiles.active=activeprofilewithdifferentsubdoc,activeprofilewithdifferentsubdoc2"); String property = this.context.getEnvironment().getProperty("foobar"); assertThat(property).isEqualTo("baz"); } @Test public void addBeforeDefaultProperties() throws Exception { MapPropertySource defaultSource = new MapPropertySource("defaultProperties", Collections.<String, Object>singletonMap("the.property", "fromdefaultproperties")); this.environment.getPropertySources().addFirst(defaultSource); this.initializer.setSearchNames("testproperties"); this.initializer.postProcessEnvironment(this.environment, this.application); String property = this.environment.getProperty("the.property"); assertThat(property).isEqualTo("frompropertiesfile"); } @Test public void customDefaultProfile() throws Exception { SpringApplication application = new SpringApplication(Config.class); application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run("--spring.profiles.default=customdefault"); String property = this.context.getEnvironment().getProperty("customdefault"); assertThat(property).isEqualTo("true"); } @Test public void customDefaultProfileAndActive() throws Exception { SpringApplication application = new SpringApplication(Config.class); application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run("--spring.profiles.default=customdefault", "--spring.profiles.active=dev"); String property = this.context.getEnvironment().getProperty("my.property"); assertThat(property).isEqualTo("fromdevpropertiesfile"); assertThat(this.context.getEnvironment().containsProperty("customdefault")) .isFalse(); } @Test public void customDefaultProfileAndActiveFromFile() throws Exception { // gh-5998 SpringApplication application = new SpringApplication(Config.class); application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run("--spring.config.name=customprofile", "--spring.profiles.default=customdefault"); ConfigurableEnvironment environment = this.context.getEnvironment(); assertThat(environment.containsProperty("customprofile")).isTrue(); assertThat(environment.containsProperty("customprofile-specific")).isTrue(); assertThat(environment.containsProperty("customprofile-customdefault")).isTrue(); assertThat(environment.acceptsProfiles("customdefault")).isTrue(); } @Test public void additionalProfilesCanBeIncludedFromAnyPropertySource() throws Exception { SpringApplication application = new SpringApplication(Config.class); application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run("--spring.profiles.active=myprofile", "--spring.profiles.include=dev"); String property = this.context.getEnvironment().getProperty("my.property"); assertThat(property).isEqualTo("fromdevpropertiesfile"); assertThat(this.context.getEnvironment().containsProperty("customdefault")) .isFalse(); } @Test public void profileCanBeIncludedWithoutAnyBeingActive() throws Exception { SpringApplication application = new SpringApplication(Config.class); application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run("--spring.profiles.include=dev"); String property = this.context.getEnvironment().getProperty("my.property"); assertThat(property).isEqualTo("fromdevpropertiesfile"); } @Test public void activeProfilesCanBeConfiguredUsingPlaceholdersResolvedAgainstTheEnvironment() throws Exception { Map<String, Object> source = new HashMap<>(); source.put("activeProfile", "testPropertySource"); org.springframework.core.env.PropertySource<?> propertySource = new MapPropertySource( "test", source); this.environment.getPropertySources().addLast(propertySource); this.initializer.setSearchNames("testactiveprofiles"); this.initializer.postProcessEnvironment(this.environment, this.application); assertThat(this.environment.getActiveProfiles()) .containsExactly("testPropertySource"); } private Condition<ConfigurableEnvironment> matchingPropertySource( final String sourceName) { return new Condition<ConfigurableEnvironment>( "environment containing property source " + sourceName) { @Override public boolean matches(ConfigurableEnvironment value) { return value.getPropertySources().contains(sourceName); } }; } private Condition<ConfigurableEnvironment> matchingProfile(final String profile) { return new Condition<ConfigurableEnvironment>("accepts profile " + profile) { @Override public boolean matches(ConfigurableEnvironment value) { return value.acceptsProfiles(profile); } }; } @Configuration protected static class Config { } @Configuration @PropertySource("classpath:/specificlocation.properties") protected static class WithPropertySource { } @Configuration @PropertySource("classpath:/${source.location}.properties") protected static class WithPropertySourcePlaceholders { } @Configuration @PropertySource(value = "classpath:/specificlocation.properties", name = "foo") protected static class WithPropertySourceAndName { } @Configuration @PropertySource("classpath:/enableprofile.properties") protected static class WithPropertySourceInProfile { } @Configuration @PropertySource("classpath:/enableprofile-myprofile.properties") @Profile("myprofile") protected static class WithPropertySourceAndProfile { } @Configuration @PropertySource({ "classpath:/specificlocation.properties", "classpath:/moreproperties.properties" }) protected static class WithPropertySourceMultipleLocations { } @Configuration @PropertySource(value = { "classpath:/specificlocation.properties", "classpath:/moreproperties.properties" }, name = "foo") protected static class WithPropertySourceMultipleLocationsAndName { } private static class TestConfigFileApplicationListener extends ConfigFileApplicationListener { @Override List<EnvironmentPostProcessor> loadPostProcessors() { return new ArrayList<>( Arrays.asList(new LowestPrecedenceEnvironmentPostProcessor())); } } @Order(Ordered.LOWEST_PRECEDENCE) private static class LowestPrecedenceEnvironmentPostProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { assertThat(environment.getPropertySources()).hasSize(4); } } }