BootstrapConfigurationTests.java
/*
* Copyright 2012-present 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.cloud.bootstrap.config;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.bootstrap.BootstrapApplicationListener;
import org.springframework.cloud.bootstrap.TestHigherPriorityBootstrapConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
import static org.assertj.core.api.BDDAssertions.then;
/**
* @author Dave Syer
* @author Yanming Zhou
* @author Olga Maciaszek-Sharma
*/
public class BootstrapConfigurationTests {
private ConfigurableApplicationContext context;
private ConfigurableApplicationContext sibling;
@AfterEach
public void close() {
// Expected.* is bound to the PropertySourceConfiguration below
System.clearProperty("expected.name");
System.clearProperty("expected.fail");
// Used to test system properties override
System.clearProperty("bootstrap.foo");
PropertySourceConfiguration.MAP.clear();
CompositePropertySourceConfiguration.MAP1.clear();
CompositePropertySourceConfiguration.MAP2.clear();
if (context != null) {
context.close();
}
if (sibling != null) {
sibling.close();
}
}
@Test
public void pickupOnlyExternalBootstrapProperties() {
String externalPropertiesPath = getExternalProperties();
pickupOnlyExternalBootstrapProperties("spring.cloud.bootstrap.location=" + externalPropertiesPath,
"spring.config.use-legacy-processing=true");
}
@Test
public void pickupOnlyExternalBootstrapPropertiesWithAppListener() {
String externalPropertiesPath = getExternalProperties();
pickupOnlyExternalBootstrapProperties("spring.cloud.bootstrap.location=" + externalPropertiesPath,
"spring.config.use-legacy-processing=true", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void pickupOnlyExternalBootstrapProperties(String... properties) {
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(BareConfiguration.class)
.properties(properties)
.run();
then(context.getEnvironment().getProperty("info.name")).isEqualTo("externalPropertiesInfoName");
then(context.getEnvironment().getProperty("info.desc")).isNull();
then(context.getEnvironment()
.getPropertySources()
.contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap")).isTrue();
}
@Test
public void pickupAdditionalExternalBootstrapProperties() {
String externalPropertiesPath = getExternalProperties();
pickupAdditionalExternalBootstrapProperties(
"spring.cloud.bootstrap.additional-location=" + externalPropertiesPath,
"spring.config.use-legacy-processing=true");
}
@Test
public void pickupAdditionalExternalBootstrapPropertiesWithAppListener() {
String externalPropertiesPath = getExternalProperties();
pickupAdditionalExternalBootstrapProperties(
"spring.cloud.bootstrap.additional-location=" + externalPropertiesPath,
"spring.config.use-legacy-processing=true", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void pickupAdditionalExternalBootstrapProperties(String... properties) {
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(BareConfiguration.class)
.properties(properties)
.run();
then(context.getEnvironment().getProperty("info.name")).isEqualTo("externalPropertiesInfoName");
then(context.getEnvironment().getProperty("info.desc")).isEqualTo("defaultPropertiesInfoDesc");
then(context.getEnvironment()
.getPropertySources()
.contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap")).isTrue();
}
@Test
public void bootstrapPropertiesAvailableInInitializer() {
bootstrapPropertiesAvailableInInitializer("spring.config.use-legacy-processing=true");
}
@Test
public void bootstrapPropertiesAvailableInInitializerWithAppContext() {
bootstrapPropertiesAvailableInInitializer("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void bootstrapPropertiesAvailableInInitializer(String... properties) {
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.initializers(applicationContext -> {
// This property is defined in bootstrap.properties
then(applicationContext.getEnvironment().getProperty("info.name")).isEqualTo("child");
})
.run();
then(context.getEnvironment()
.getPropertySources()
.contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap")).isTrue();
}
/**
* Running the test from maven will start from a different directory then starting it
* from intellij
* @return external properties resource location
*/
private String getExternalProperties() {
String externalPropertiesPath = "classpath:external-properties/bootstrap.properties";
return externalPropertiesPath;
}
@Test
public void picksUpAdditionalPropertySource() {
picksUpAdditionalPropertySource("spring.config.use-legacy-processing=true");
}
@Test
public void picksUpAdditionalPropertySourceWithAppContext() {
picksUpAdditionalPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void picksUpAdditionalPropertySource(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
then(context.getEnvironment()
.getPropertySources()
.contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap")).isTrue();
}
@Test
public void failsOnPropertySource() {
failsOnPropertySource("spring.config.use-legacy-processing=true");
}
@Test
public void failsOnPropertySourceWithAppContext() {
failsOnPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void failsOnPropertySource(String... properties) {
System.setProperty("expected.fail", "true");
assertThatRuntimeException()
.isThrownBy(() -> context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run())
.withMessage("Planned");
}
@Test
public void overrideSystemPropertySourceByDefault() {
overrideSystemPropertySourceByDefault("spring.config.use-legacy-processing=true");
}
@Test
public void overrideSystemPropertySourceByDefaultWithAppContext() {
overrideSystemPropertySourceByDefault("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void overrideSystemPropertySourceByDefault(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
System.setProperty("bootstrap.foo", "system");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
}
@Test
public void systemPropertyOverrideFalse() {
systemPropertyOverrideFalse("spring.config.use-legacy-processing=true");
}
@Test
public void systemPropertyOverrideFalseWithAppContext() {
systemPropertyOverrideFalse("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void systemPropertyOverrideFalse(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideSystemProperties", "false");
System.setProperty("bootstrap.foo", "system");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("system");
}
@Test
public void systemPropertyOverrideWhenOverrideDisallowed() {
systemPropertyOverrideWhenOverrideDisallowed("spring.config.use-legacy-processing=true");
}
@Test
public void systemPropertyOverrideWhenOverrideDisallowedWithAppContext() {
systemPropertyOverrideWhenOverrideDisallowed("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void systemPropertyOverrideWhenOverrideDisallowed(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideSystemProperties", "false");
// If spring.cloud.config.allowOverride=false is in the remote property sources
// with sufficiently high priority it always wins. Admins can enforce it by adding
// their own remote property source.
PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "false");
System.setProperty("bootstrap.foo", "system");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
}
@Test
public void systemPropertyOverrideFalseWhenOverrideAllowed() {
systemPropertyOverrideFalseWhenOverrideAllowed("spring.config.use-legacy-processing=true");
}
@Test
public void systemPropertyOverrideFalseWhenOverrideAllowedWithAppContext() {
systemPropertyOverrideFalseWhenOverrideAllowed("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void systemPropertyOverrideFalseWhenOverrideAllowed(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideSystemProperties", "false");
PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "true");
System.setProperty("bootstrap.foo", "system");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("system");
}
@Test
public void overrideAllWhenOverrideAllowed() {
overrideAllWhenOverrideAllowed("spring.config.use-legacy-processing=true");
}
@Test
public void overrideAllWhenOverrideAllowedWithAppContext() {
overrideAllWhenOverrideAllowed("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void overrideAllWhenOverrideAllowed(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideNone", "true");
PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "true");
ConfigurableEnvironment environment = new StandardEnvironment();
environment.getPropertySources()
.addLast(new MapPropertySource("last", Collections.<String, Object>singletonMap("bootstrap.foo", "splat")));
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.environment(environment)
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("splat");
}
@Test
public void applicationNameInBootstrapAndMain() {
applicationNameInBootstrapAndMain("spring.cloud.bootstrap.name:other",
"spring.config.use-legacy-processing=true", "spring.config.name:plain");
}
@Test
public void applicationNameInBootstrapAndMainWithAppContext() {
applicationNameInBootstrapAndMain("spring.cloud.bootstrap.name:other",
"spring.config.use-legacy-processing=true", "spring.config.name:plain",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void applicationNameInBootstrapAndMain(String... properties) {
System.setProperty("expected.name", "main");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().getProperty("spring.application.name")).isEqualTo("app");
// The parent is called "main" because spring.application.name is specified in
// other.properties (the bootstrap properties)
then(context.getParent().getEnvironment().getProperty("spring.application.name")).isEqualTo("main");
// The bootstrap context has the same "bootstrap" property source
then(((ConfigurableEnvironment) context.getParent().getEnvironment()).getPropertySources().get("bootstrap"))
.isEqualTo(context.getEnvironment().getPropertySources().get("bootstrap"));
then(context.getId()).isEqualTo("main-1");
}
@Test
public void applicationNameNotInBootstrap() {
applicationNameNotInBootstrap("spring.cloud.bootstrap.name:application",
"spring.config.use-legacy-processing=true", "spring.config.name:other");
}
@Test
public void applicationNameNotInBootstrapWithAppContext() {
applicationNameNotInBootstrap("spring.cloud.bootstrap.name:application",
"spring.config.use-legacy-processing=true", "spring.config.name:other",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void applicationNameNotInBootstrap(String... properties) {
System.setProperty("expected.name", "main");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().getProperty("spring.application.name")).isEqualTo("main");
// The parent has no name because spring.application.name is not
// defined in the bootstrap properties
then(context.getParent().getEnvironment().getProperty("spring.application.name")).isEqualTo(null);
}
@Test
public void applicationNameOnlyInBootstrap() {
applicationNameOnlyInBootstrap("spring.cloud.bootstrap.name:other", "spring.config.use-legacy-processing=true");
}
@Test
public void applicationNameOnlyInBootstrapWithAppContext() {
applicationNameOnlyInBootstrap("spring.cloud.bootstrap.name:other", "spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void applicationNameOnlyInBootstrap(String... properties) {
System.setProperty("expected.name", "main");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run();
// The main context is called "main" because spring.application.name is specified
// in other.properties (and not in the main config file)
then(context.getEnvironment().getProperty("spring.application.name")).isEqualTo("main");
// The parent is called "main" because spring.application.name is specified in
// other.properties (the bootstrap properties this time)
then(context.getParent().getEnvironment().getProperty("spring.application.name")).isEqualTo("main");
then(context.getId()).isEqualTo("main-1");
}
@Test
public void environmentEnrichedOnceWhenSharedWithChildContext() {
environmentEnrichedOnceWhenSharedWithChildContext("spring.config.use-legacy-processing=true");
}
@Test
public void environmentEnrichedOnceWhenSharedWithChildContextWithAppContext() {
environmentEnrichedOnceWhenSharedWithChildContext("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void environmentEnrichedOnceWhenSharedWithChildContext(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
context = new SpringApplicationBuilder().sources(BareConfiguration.class)
.properties(properties)
.environment(new StandardEnvironment())
.child(BareConfiguration.class)
.web(WebApplicationType.NONE)
.run();
then(context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
then(context.getParent().getEnvironment()).isEqualTo(context.getEnvironment());
MutablePropertySources sources = context.getEnvironment().getPropertySources();
PropertySource<?> bootstrap = sources
.get(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap");
then(bootstrap).isNotNull();
then(sources.precedenceOf(bootstrap)).isEqualTo(0);
}
@Test
public void onlyOneBootstrapContext() {
onlyOneBootstrapContext("spring.config.use-legacy-processing=true");
}
@Test
public void onlyOneBootstrapContextWithAppContext() {
onlyOneBootstrapContext("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void onlyOneBootstrapContext(String... properties) {
TestHigherPriorityBootstrapConfiguration.count.set(0);
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
context = new SpringApplicationBuilder().sources(BareConfiguration.class)
.properties(properties)
.child(BareConfiguration.class)
.web(WebApplicationType.NONE)
.run();
then(TestHigherPriorityBootstrapConfiguration.count.get()).isEqualTo(1);
then(context.getParent()).isNotNull();
then(context.getParent().getParent().getId()).isEqualTo("bootstrap");
then(context.getParent().getParent().getParent()).isNull();
then(context.getEnvironment().getProperty("custom.foo")).isEqualTo("bar");
}
@Test
public void listOverride() {
listOverride("spring.config.use-legacy-processing=true");
}
@Test
public void listOverrideWithAppContext() {
listOverride("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void listOverride(String... properties) {
context = new SpringApplicationBuilder().sources(BareConfiguration.class)
.properties(properties)
.child(BareConfiguration.class)
.web(WebApplicationType.NONE)
.run();
ListProperties listProperties = new ListProperties();
Binder.get(context.getEnvironment()).bind("list", Bindable.ofInstance(listProperties));
then(listProperties.getFoo().size()).isEqualTo(1);
then(listProperties.getFoo().get(0)).isEqualTo("hello world");
}
@Test
public void bootstrapContextSharedBySiblings() {
bootstrapContextSharedBySiblings("spring.config.use-legacy-processing=true");
}
@Test
public void bootstrapContextSharedBySiblingsWithAppContext() {
bootstrapContextSharedBySiblings("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void bootstrapContextSharedBySiblings(String... properties) {
TestHigherPriorityBootstrapConfiguration.count.set(0);
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
SpringApplicationBuilder builder = new SpringApplicationBuilder().properties(properties)
.sources(BareConfiguration.class);
sibling = builder.child(BareConfiguration.class)
.properties("spring.application.name=sibling")
.web(WebApplicationType.NONE)
.run();
context = builder.child(BareConfiguration.class)
.properties("spring.application.name=context")
.web(WebApplicationType.NONE)
.run();
then(TestHigherPriorityBootstrapConfiguration.count.get()).isEqualTo(1);
then(context.getParent()).isNotNull();
then(context.getParent().getParent().getId()).isEqualTo("bootstrap");
then(context.getParent().getParent().getParent()).isNull();
then(context.getEnvironment().getProperty("custom.foo")).isEqualTo("context");
then(context.getEnvironment().getProperty("spring.application.name")).isEqualTo("context");
then(sibling.getParent()).isNotNull();
then(sibling.getParent().getParent().getId()).isEqualTo("bootstrap");
then(sibling.getParent().getParent().getParent()).isNull();
then(sibling.getEnvironment().getProperty("custom.foo")).isEqualTo("sibling");
then(sibling.getEnvironment().getProperty("spring.application.name")).isEqualTo("sibling");
}
@Test
public void environmentEnrichedInParentContext() {
environmentEnrichedInParentContext("spring.config.use-legacy-processing=true");
}
@Test
public void environmentEnrichedInParentContextWithAppContext() {
environmentEnrichedInParentContext("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void environmentEnrichedInParentContext(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
context = new SpringApplicationBuilder().sources(BareConfiguration.class)
.properties(properties)
.child(BareConfiguration.class)
.web(WebApplicationType.NONE)
.run();
then(context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
then(context.getParent().getEnvironment()).isNotSameAs(context.getEnvironment());
then(context.getEnvironment()
.getPropertySources()
.contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap")).isTrue();
then(((ConfigurableEnvironment) context.getParent().getEnvironment()).getPropertySources()
.contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap")).isTrue();
}
@Test
@Disabled // FIXME: legacy
public void differentProfileInChild() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
// Profiles are always merged with the child
ConfigurableApplicationContext parent = new SpringApplicationBuilder().sources(BareConfiguration.class)
.profiles("parent")
.web(WebApplicationType.NONE)
.run();
context = new SpringApplicationBuilder(BareConfiguration.class)
.properties("spring.config.use-legacy-processing=true")
.profiles("child")
.parent(parent)
.web(WebApplicationType.NONE)
.run();
then(context.getParent().getEnvironment()).isNotSameAs(context.getEnvironment());
// The ApplicationContext merges profiles (profiles and property sources), see
// AbstractEnvironment.merge()
then(context.getEnvironment().acceptsProfiles("child", "parent")).isTrue();
// But the parent is not a child
then(context.getParent().getEnvironment().acceptsProfiles("child")).isFalse();
then(context.getParent().getEnvironment().acceptsProfiles("parent")).isTrue();
then(((ConfigurableEnvironment) context.getParent().getEnvironment()).getPropertySources()
.contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap")).isTrue();
then(context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
// The "bootstrap" property source is not shared now, but it has the same
// properties in it because they are pulled from the PropertySourceConfiguration
// below
then(context.getParent().getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
// The parent property source is there in the child because they are both in the
// "parent" profile (by virtue of the merge in AbstractEnvironment)
then(context.getEnvironment().getProperty("info.name")).isEqualTo("parent");
}
@Test
public void includeProfileFromBootstrapPropertySource() {
includeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true");
}
@Test
public void includeProfileFromBootstrapPropertySourceWithAppContext() {
includeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void includeProfileFromBootstrapPropertySource(String... properties) {
PropertySourceConfiguration.MAP.put("spring.profiles.include", "bar,baz");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.profiles("foo")
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().acceptsProfiles("baz")).isTrue();
then(context.getEnvironment().acceptsProfiles("bar")).isTrue();
}
@Test
public void activeProfileFromBootstrapPropertySource() {
activeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true");
then(context.getEnvironment().getActiveProfiles()).contains("foo");
}
@Test
public void activeProfileFromBootstrapPropertySourceWithAppContext() {
activeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
then(context.getEnvironment().getActiveProfiles()).doesNotContain("after");
then(context.getEnvironment().getActiveProfiles()).contains("baz", "bar", "foo");
}
private void activeProfileFromBootstrapPropertySource(String... properties) {
PropertySourceConfiguration.MAP.put("spring.profiles.active", "bar,baz");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.profiles("foo")
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().acceptsProfiles("baz", "bar", "foo")).isTrue();
}
@Test
public void activeAndIncludeProfileFromBootstrapPropertySource() {
activeAndIncludeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true");
}
@Test
public void activeAndIncludeProfileFromBootstrapPropertySourceWithAppContext() {
activeAndIncludeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void activeAndIncludeProfileFromBootstrapPropertySource(String... properties) {
PropertySourceConfiguration.MAP.put("spring.profiles.active", "bar,baz");
PropertySourceConfiguration.MAP.put("spring.profiles.include", "bar,baz,hello");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.profiles("foo")
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().acceptsProfiles("baz", "bar", "hello", "foo")).isTrue();
then(context.getEnvironment().getActiveProfiles()).contains("baz", "bar", "foo", "hello");
}
@Test
public void activeAndIncludeProfileFromBootstrapPropertySourceWithReplacement() {
activeAndIncludeProfileFromBootstrapPropertySourceWithReplacement("spring.config.use-legacy-processing=true",
"barreplacement=bar");
}
@Test
public void activeAndIncludeProfileFromBootstrapPropertySourceWithReplacementWithAppContext() {
activeAndIncludeProfileFromBootstrapPropertySourceWithReplacement("spring.config.use-legacy-processing=true",
"barreplacement=bar", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void activeAndIncludeProfileFromBootstrapPropertySourceWithReplacement(String... properties) {
PropertySourceConfiguration.MAP.put("spring.profiles.active", "${barreplacement},baz");
PropertySourceConfiguration.MAP.put("spring.profiles.include", "${barreplacement},baz,hello");
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.profiles("foo")
.sources(BareConfiguration.class)
.run();
then(context.getEnvironment().acceptsProfiles("baz", "bar", "hello", "foo")).isTrue();
then(context.getEnvironment().getActiveProfiles()).contains("baz", "bar", "foo", "hello");
}
@Test
public void includeProfileFromBootstrapProperties() {
includeProfileFromBootstrapProperties("spring.config.use-legacy-processing=true",
"spring.cloud.bootstrap.name=local");
}
@Test
public void includeProfileFromBootstrapPropertiesWithAppContext() {
includeProfileFromBootstrapProperties("spring.config.use-legacy-processing=true",
"spring.cloud.bootstrap.name=local", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void includeProfileFromBootstrapProperties(String... properties) {
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(BareConfiguration.class)
.properties(properties)
.run();
then(context.getEnvironment().acceptsProfiles("local")).isTrue();
then(context.getEnvironment().getProperty("added")).isEqualTo("Hello added!");
}
@Test
public void nonEnumerablePropertySourceWorks() {
nonEnumerablePropertySourceWorks("spring.config.use-legacy-processing=true",
"spring.cloud.bootstrap.name=nonenumerable");
}
@Test
public void nonEnumerablePropertySourceWorksWithAppContext() {
nonEnumerablePropertySourceWorks("spring.config.use-legacy-processing=true",
"spring.cloud.bootstrap.name=nonenumerable", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void nonEnumerablePropertySourceWorks(String... properties) {
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(BareConfiguration.class)
.properties(properties)
.run();
then(context.getEnvironment().getProperty("foo")).isEqualTo("bar");
}
@Test
void activeAndIncludeProfileFromBootstrapPropertySource_WhenMultiplePlacesHaveActiveProfileProperties_ShouldOnlyAcceptTheTopPriority() {
String[] properties = new String[] { "spring.config.use-legacy-processing=true" };
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.properties(properties)
.sources(BareConfiguration.class)
.run("--spring.profiles.active=prod,secure");
then(context.getEnvironment().acceptsProfiles("prod", "secure")).isTrue();
// active profile from property sources with lower priority should not be included
then(context.getEnvironment().acceptsProfiles("local")).isFalse();
then(context.getEnvironment().getActiveProfiles()).contains("prod", "secure");
then(context.getEnvironment().getActiveProfiles()).doesNotContain("local");
// check if active profile value could possibly exist in other property sources
// with lower priority
then(context.getEnvironment()
.getPropertySources()
.stream()
.map(p -> p.getProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME))
.anyMatch("local"::equals)).isTrue();
}
@Test // GH-1416
public void bootstrapPropertiesWithActivateOnProfile() {
String bootstrapLocation = "spring.cloud.bootstrap.location=classpath:external-properties/bootstrap.yaml";
String legacyProcessing = "spring.config.use-legacy-processing=true";
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(BareConfiguration.class)
.properties(bootstrapLocation, legacyProcessing)
.run();
then(this.context.getEnvironment().getProperty("info.name")).isEqualTo("externalPropertiesInfoName");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(BareConfiguration.class)
.properties(bootstrapLocation, legacyProcessing, "spring.profiles.active=bar")
.run();
then(this.context.getEnvironment().getProperty("info.name")).isEqualTo("externalPropertiesInfoName from bar");
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
protected static class BareConfiguration {
}
@Configuration(proxyBeanMethods = false)
// This is added to bootstrap context as a source in bootstrap.properties
protected static class SimplePropertySourceConfiguration implements PropertySourceLocator {
@Override
public PropertySource<?> locate(Environment environment) {
return new PropertySource("testBootstrapSimple", this) {
@Override
public Object getProperty(String name) {
return ("foo".equals(name)) ? "bar" : null;
}
};
}
}
@Configuration(proxyBeanMethods = false)
@ConfigurationProperties("expected")
// This is added to bootstrap context as a source in bootstrap.properties
protected static class PropertySourceConfiguration implements PropertySourceLocator {
public static Map<String, Object> MAP = new HashMap<>(
Collections.<String, Object>singletonMap("bootstrap.foo", "bar"));
private String name;
private boolean fail = false;
@Override
public PropertySource<?> locate(Environment environment) {
if (environment instanceof ConfigurableEnvironment) {
if (!((ConfigurableEnvironment) environment).getPropertySources()
.contains(BootstrapApplicationListener.BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
if (MAP.containsKey(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME)) {
// This additional profile, after, should not be added when
// initialize-on-context-refresh=true
MAP.put(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME,
MAP.get(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME) + ",after");
}
}
}
if (name != null) {
then(name).isEqualTo(environment.getProperty("spring.application.name"));
}
if (fail) {
throw new RuntimeException("Planned");
}
return new MapPropertySource("testBootstrap", MAP);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isFail() {
return fail;
}
public void setFail(boolean fail) {
this.fail = fail;
}
}
@Configuration
@ConfigurationProperties("compositeexpected")
// This is added to bootstrap context as a source in bootstrap.properties
protected static class CompositePropertySourceConfiguration implements PropertySourceLocator {
public static Map<String, Object> MAP1 = new HashMap<>();
public static Map<String, Object> MAP2 = new HashMap<>();
public CompositePropertySourceConfiguration() {
MAP1.put("list.foo[0]", "hello");
MAP1.put("list.food[1]", "world");
MAP2.put("list.foo[0]", "hello world");
}
private String name;
private boolean fail = false;
@Override
public PropertySource<?> locate(Environment environment) {
if (name != null) {
then(name).isEqualTo(environment.getProperty("spring.application.name"));
}
if (fail) {
throw new RuntimeException("Planned");
}
CompositePropertySource compositePropertySource = new CompositePropertySource("listTestBootstrap");
compositePropertySource.addFirstPropertySource(new MapPropertySource("testBootstrap1", MAP1));
compositePropertySource.addFirstPropertySource(new MapPropertySource("testBootstrap2", MAP2));
return compositePropertySource;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isFail() {
return fail;
}
public void setFail(boolean fail) {
this.fail = fail;
}
}
protected static class ListProperties {
private List<String> foo;
public List<String> getFoo() {
return foo;
}
public void setFoo(List<String> foo) {
this.foo = foo;
}
}
}