diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/BeanDefinitionLoaderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/BeanDefinitionLoaderTests.java
index 86c30311a7f9..e4de8e40ba37 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/BeanDefinitionLoaderTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/BeanDefinitionLoaderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -23,6 +23,7 @@
import org.springframework.boot.sampleconfig.MyComponent;
import org.springframework.boot.sampleconfig.MyNamedComponent;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.io.ClassPathResource;
@@ -72,8 +73,9 @@ void loadJsr330Class() {
}
@Test
+ @WithSampleBeansXmlResource
void loadXmlResource() {
- ClassPathResource resource = new ClassPathResource("sample-beans.xml", getClass());
+ ClassPathResource resource = new ClassPathResource("org/springframework/boot/sample-beans.xml");
BeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, resource);
assertThat(load(loader)).isOne();
assertThat(this.registry.containsBean("myXmlComponent")).isTrue();
@@ -81,8 +83,15 @@ void loadXmlResource() {
}
@Test
+ @WithResource(name = "org/springframework/boot/sample-beans.groovy", content = """
+ import org.springframework.boot.sampleconfig.MyComponent;
+
+ beans {
+ myGroovyComponent(MyComponent) {}
+ }
+ """)
void loadGroovyResource() {
- ClassPathResource resource = new ClassPathResource("sample-beans.groovy", getClass());
+ ClassPathResource resource = new ClassPathResource("org/springframework/boot/sample-beans.groovy");
BeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, resource);
assertThat(load(loader)).isOne();
assertThat(this.registry.containsBean("myGroovyComponent")).isTrue();
@@ -90,8 +99,17 @@ void loadGroovyResource() {
}
@Test
+ @WithResource(name = "org/springframework/boot/sample-namespace.groovy", content = """
+ import org.springframework.boot.sampleconfig.MyComponent;
+
+ beans {
+ xmlns([ctx:'http://www.springframework.org/schema/context'])
+ ctx.'component-scan'('base-package':'nonexistent')
+ myGroovyComponent(MyComponent) {}
+ }
+ """)
void loadGroovyResourceWithNamespace() {
- ClassPathResource resource = new ClassPathResource("sample-namespace.groovy", getClass());
+ ClassPathResource resource = new ClassPathResource("org/springframework/boot/sample-namespace.groovy");
BeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, resource);
assertThat(load(loader)).isOne();
assertThat(this.registry.containsBean("myGroovyComponent")).isTrue();
@@ -114,7 +132,8 @@ void loadClassName() {
}
@Test
- void loadResourceName() {
+ @WithSampleBeansXmlResource
+ void loadXmlName() {
BeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry,
"classpath:org/springframework/boot/sample-beans.xml");
assertThat(load(loader)).isOne();
@@ -122,6 +141,13 @@ void loadResourceName() {
}
@Test
+ @WithResource(name = "org/springframework/boot/sample-beans.groovy", content = """
+ import org.springframework.boot.sampleconfig.MyComponent;
+
+ beans {
+ myGroovyComponent(MyComponent) {}
+ }
+ """)
void loadGroovyName() {
BeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry,
"classpath:org/springframework/boot/sample-beans.groovy");
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SimpleMainTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SimpleMainTests.java
index 2db0367d3858..924a80d9977d 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SimpleMainTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SimpleMainTests.java
@@ -61,12 +61,14 @@ void configClassContext(CapturedOutput output) throws Exception {
}
@Test
+ @WithSampleBeansXmlResource
void xmlContext(CapturedOutput output) throws Exception {
SpringApplication.main(getArgs("org/springframework/boot/sample-beans.xml"));
assertThat(output).contains(SPRING_STARTUP);
}
@Test
+ @WithSampleBeansXmlResource
void mixedContext(CapturedOutput output) throws Exception {
SpringApplication.main(getArgs(getClass().getName(), "org/springframework/boot/sample-beans.xml"));
assertThat(output).contains(SPRING_STARTUP);
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationBannerPrinterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationBannerPrinterTests.java
index 50250c8c0c00..1335c0aa690e 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationBannerPrinterTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationBannerPrinterTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -22,6 +22,7 @@
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
@@ -47,9 +48,10 @@ void shouldRegisterRuntimeHints() {
}
@Test
+ @WithResource(name = "banner.txt", content = "\uD83D\uDE0D Spring Boot! \uD83D\uDE0D")
void shouldUseUtf8() {
ResourceLoader resourceLoader = new GenericApplicationContext();
- Resource resource = resourceLoader.getResource("classpath:/banner-utf8.txt");
+ Resource resource = resourceLoader.getResource("classpath:banner.txt");
SpringApplicationBannerPrinter printer = new SpringApplicationBannerPrinter(resourceLoader,
new ResourceBanner(resource));
Log log = mock(Log.class);
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java
index 681e7ca881a0..3117b3d4446e 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java
@@ -72,6 +72,7 @@
import org.springframework.boot.context.event.SpringApplicationEvent;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
@@ -226,19 +227,24 @@ void sourcesMustBeAccessible() {
}
@Test
+ @WithResource(name = "banner.txt", content = "Running a Test!")
void customBanner(CapturedOutput output) {
SpringApplication application = spy(new SpringApplication(ExampleConfig.class));
application.setWebApplicationType(WebApplicationType.NONE);
- this.context = application.run("--spring.banner.location=classpath:test-banner.txt");
+ this.context = application.run();
assertThat(output).startsWith("Running a Test!");
+
}
@Test
+ @WithResource(name = "banner.txt", content = """
+ Running a Test!
+
+ ${test.property}""")
void customBannerWithProperties(CapturedOutput output) {
SpringApplication application = spy(new SpringApplication(ExampleConfig.class));
application.setWebApplicationType(WebApplicationType.NONE);
- this.context = application.run("--spring.banner.location=classpath:test-banner-with-placeholder.txt",
- "--test.property=123456");
+ this.context = application.run("--test.property=123456");
assertThat(output).containsPattern("Running a Test!\\s+123456");
}
@@ -288,6 +294,7 @@ void enableBannerInLogViaProperty(CapturedOutput output) {
}
@Test
+ @WithResource(name = "bindtoapplication.properties", content = "spring.main.banner-mode=off")
void triggersConfigFileApplicationListenerBeforeBinding() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@@ -539,6 +546,7 @@ void commandLinePropertySourceEnhancesEnvironment() {
}
@Test
+ @WithResource(name = "application.properties", content = "foo=bucket")
void propertiesFileEnhancesEnvironment() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@@ -571,6 +579,8 @@ void additionalProfilesOrderedBeforeActiveProfiles() {
}
@Test
+ @WithResource(name = "application.properties", content = "my.property=fromapplicationproperties")
+ @WithResource(name = "application-other.properties", content = "my.property=fromotherpropertiesfile")
void addProfilesOrderWithProperties() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@@ -583,6 +593,7 @@ void addProfilesOrderWithProperties() {
}
@Test
+ @WithResource(name = "application.properties", content = "foo=bucket")
void emptyCommandLinePropertySourceNotAdded() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@@ -813,11 +824,13 @@ void loadSources() {
}
@Test
+ @WithSampleBeansXmlResource
+ @WithResource(name = "application.properties", content = "sample.app.test.prop=*")
void wildcardSources() {
TestSpringApplication application = new TestSpringApplication();
application.getSources().add("classpath*:org/springframework/boot/sample-${sample.app.test.prop}.xml");
application.setWebApplicationType(WebApplicationType.NONE);
- this.context = application.run();
+ this.context = application.run("--spring.config.location=classpath:/");
}
@Test
@@ -1138,6 +1151,8 @@ void reactiveApplicationConfiguredViaAPropertyHasTheCorrectTypeOfContextAndEnvir
}
@Test
+ @WithResource(name = "application-withwebapplicationtype.yml",
+ content = "spring.main.web-application-type: reactive")
void environmentIsConvertedIfTypeDoesNotMatch() {
ConfigurableApplicationContext context = new SpringApplication(ExampleReactiveWebConfig.class)
.run("--spring.profiles.active=withwebapplicationtype");
@@ -1194,6 +1209,7 @@ void circularReferencesCanBeEnabled() {
}
@Test
+ @WithResource(name = "custom-config/application.yml", content = "hello: world")
void relaxedBindingShouldWorkBeforeEnvironmentIsPrepared() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@@ -1328,6 +1344,8 @@ void bindsEnvironmentPrefixToSpringApplication() {
}
@Test
+ @WithResource(name = "spring-application-config-property-source.properties",
+ content = "test.name=spring-application-config-property-source")
void movesConfigClassPropertySourcesToEnd() {
SpringApplication application = new SpringApplication(PropertySourceConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/WithSampleBeansXmlResource.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/WithSampleBeansXmlResource.java
new file mode 100644
index 000000000000..91359f63bcfb
--- /dev/null
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/WithSampleBeansXmlResource.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-2025 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.boot;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
+
+/**
+ * Makes an {@code org/springframework/boot/sample-beans.xml} resource available from the
+ * thread context classloader.
+ *
+ * @author Andy Wilkinson
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@WithResource(name = "org/springframework/boot/sample-beans.xml",
+ content = """
+
+
+
+
+ """)
+@interface WithSampleBeansXmlResource {
+
+}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java
index c5341c8fd945..3f4b5a4ed9f5 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -29,6 +29,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationShutdownHookInstance;
import org.springframework.boot.WebApplicationType;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -72,14 +73,21 @@ private void close(ApplicationContext context) {
}
@Test
+ @WithResource(name = "application.properties", content = """
+ b=file
+ c=file
+ """)
+ @WithResource(name = "application-foo.properties", content = "b=profile-specific-file")
void profileAndProperties() {
SpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)
.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class))
.profiles("foo")
- .properties("foo=bar");
+ .properties("a=default");
this.context = application.run();
assertThat(this.context).isInstanceOf(StaticApplicationContext.class);
- assertThat(this.context.getEnvironment().getProperty("foo")).isEqualTo("bucket");
+ assertThat(this.context.getEnvironment().getProperty("a")).isEqualTo("default");
+ assertThat(this.context.getEnvironment().getProperty("b")).isEqualTo("profile-specific-file");
+ assertThat(this.context.getEnvironment().getProperty("c")).isEqualTo("file");
assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("foo"))).isTrue();
}
@@ -194,6 +202,7 @@ void parentFirstCreation() {
}
@Test
+ @WithResource(name = "application-node.properties", content = "bar=spam")
void parentFirstCreationWithProfileAndDefaultArgs() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class).profiles("node")
.properties("transport=redis")
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/annotation/ImportCandidatesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/annotation/ImportCandidatesTests.java
index 2d4551f00edf..8af49ee43a1e 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/annotation/ImportCandidatesTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/annotation/ImportCandidatesTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -23,6 +23,8 @@
import org.junit.jupiter.api.Test;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
+
import static org.assertj.core.api.Assertions.assertThat;
/**
@@ -32,7 +34,18 @@
*/
class ImportCandidatesTests {
+ private static final String IMPORTS_FILE = "META-INF/spring/org.springframework.boot.context.annotation.ImportCandidatesTests$TestAnnotation.imports";
+
@Test
+ @WithResource(name = IMPORTS_FILE, content = """
+ # A comment spanning a complete line
+ class1
+
+ class2 # with comment at the end
+ # Comment with some whitespace in front
+ class3
+
+ """)
void loadReadsFromClasspathFile() {
ImportCandidates candidates = ImportCandidates.load(TestAnnotation.class, null);
assertThat(candidates).containsExactly("class1", "class2", "class3");
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/AnsiOutputApplicationListenerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/AnsiOutputApplicationListenerTests.java
index 75c4b9bbcd67..cf198bf2c237 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/AnsiOutputApplicationListenerTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/AnsiOutputApplicationListenerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2019 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -28,11 +28,9 @@
import org.springframework.boot.ansi.AnsiOutput;
import org.springframework.boot.ansi.AnsiOutput.Enabled;
import org.springframework.boot.ansi.AnsiOutputEnabledValue;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.StandardEnvironment;
-import org.springframework.test.context.support.TestPropertySourceUtils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -81,11 +79,9 @@ void disabled() {
}
@Test
+ @WithResource(name = "application.properties", content = "spring.output.ansi.enabled=never")
void disabledViaApplicationProperties() {
- ConfigurableEnvironment environment = new StandardEnvironment();
- TestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, "spring.config.name=ansi");
SpringApplication application = new SpringApplication(Config.class);
- application.setEnvironment(environment);
application.setWebApplicationType(WebApplicationType.NONE);
this.context = application.run();
assertThat(AnsiOutputEnabledValue.get()).isEqualTo(Enabled.NEVER);
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests.java
index 45d8eec77158..93a3d39efacc 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -23,6 +23,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.context.config.TestConfigDataBootstrap.LoaderHelper;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
@@ -45,9 +46,24 @@ void setup() {
}
@Test
+ @WithResource(name = "imported.properties", content = """
+ spring.config.import=testbootstrap:test
+ spring.profiles.active=test
+ myprop=igotbound
+ #---
+ spring.config.activate.on-profile=test
+ myprofileprop=igotprofilebound
+
+ """)
+ @WithResource(name = "META-INF/spring.factories", content = """
+ org.springframework.boot.context.config.ConfigDataLoader=\
+ org.springframework.boot.context.config.TestConfigDataBootstrap.Loader
+ org.springframework.boot.context.config.ConfigDataLocationResolver=\
+ org.springframework.boot.context.config.TestConfigDataBootstrap.LocationResolver
+ """)
void bootstrapsApplicationContext() {
try (ConfigurableApplicationContext context = this.application
- .run("--spring.config.import=classpath:application-bootstrap-registry-integration-tests.properties")) {
+ .run("--spring.config.import=classpath:imported.properties")) {
LoaderHelper bean = context.getBean(TestConfigDataBootstrap.LoaderHelper.class);
assertThat(bean).isNotNull();
assertThat(bean.getBound()).isEqualTo("igotbound");
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.java
index 0b9f5e58c621..c4e28c206d59 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -33,6 +33,7 @@
import org.springframework.boot.context.config.ConfigData.Option;
import org.springframework.boot.context.config.ConfigData.Options;
import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests.Config;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
@@ -45,6 +46,18 @@
*
* @author Phillip Webb
*/
+@WithResource(name = "application.properties", content = """
+ spring.config.import=icwps:
+ prop=fromfile
+ """)
+@WithResource(name = "application-prod.properties", content = "prop=fromprofilefile")
+@WithResource(name = "META-INF/spring.factories",
+ content = """
+ org.springframework.boot.context.config.ConfigDataLoader=\
+ org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.Loader
+ org.springframework.boot.context.config.ConfigDataLocationResolver=\
+ org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.LocationResolver
+ """)
class ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests {
private SpringApplication application;
@@ -60,16 +73,14 @@ void setup() {
@Test
void testWithoutProfile() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.name=configimportwithprofilespecific");
+ ConfigurableApplicationContext context = this.application.run();
String value = context.getEnvironment().getProperty("prop");
assertThat(value).isEqualTo("fromicwps1");
}
@Test
void testWithProfile() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.name=configimportwithprofilespecific", "--spring.profiles.active=prod");
+ ConfigurableApplicationContext context = this.application.run("--spring.profiles.active=prod");
String value = context.getEnvironment().getProperty("prop");
assertThat(value).isEqualTo("fromicwps2");
}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java
index 940db092ec43..12005f44db17 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,16 +20,17 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.UUID;
-import org.apache.logging.log4j.util.Strings;
import org.assertj.core.api.Condition;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -46,6 +47,9 @@
import org.springframework.boot.context.properties.source.ConfigurationProperty;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
import org.springframework.boot.origin.Origin;
+import org.springframework.boot.testsupport.BuildOutput;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
+import org.springframework.boot.testsupport.classpath.resources.WithResourceDirectory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
@@ -59,6 +63,7 @@
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.FileCopyUtils;
+import org.springframework.util.FileSystemUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -115,6 +120,7 @@ public ClassLoader getClassLoader() {
}
@Test
+ @WithResource(name = "application.properties", content = "foo=bucket")
void runLoadsApplicationPropertiesOnClasspath() {
ConfigurableApplicationContext context = this.application.run();
String property = context.getEnvironment().getProperty("foo");
@@ -122,13 +128,15 @@ void runLoadsApplicationPropertiesOnClasspath() {
}
@Test
+ @WithResource(name = "application.yaml", content = "yamlkey: yamlvalue")
void runLoadsApplicationYamlOnClasspath() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=customapplication");
+ ConfigurableApplicationContext context = this.application.run();
String property = context.getEnvironment().getProperty("yamlkey");
assertThat(property).isEqualTo("yamlvalue");
}
@Test
+ @WithResource(name = "testproperties.properties", content = "the.property=frompropertiesfile")
void runLoadsFileWithCustomName() {
ConfigurableApplicationContext context = this.application.run("--spring.config.name=testproperties");
String property = context.getEnvironment().getProperty("the.property");
@@ -136,45 +144,84 @@ void runLoadsFileWithCustomName() {
}
@Test
+ @WithResource(name = "application.properties", content = """
+ duplicate=properties
+ only-properties = properties
+ """)
+ @WithResource(name = "application.yaml", content = """
+ duplicate: yaml
+ only-yaml: yaml
+ """)
void runWhenPropertiesAndYamlShouldPreferProperties() {
ConfigurableApplicationContext context = this.application.run();
- String property = context.getEnvironment().getProperty("duplicate");
- assertThat(property).isEqualTo("properties");
+ assertThat(context.getEnvironment().getProperty("duplicate")).isEqualTo("properties");
+ assertThat(context.getEnvironment().getProperty("only-properties")).isEqualTo("properties");
+ assertThat(context.getEnvironment().getProperty("only-yaml")).isEqualTo("yaml");
}
@Test
+ @WithResource(name = "moreproperties.properties", content = """
+ the.property=more
+ only.more=more
+ """)
+ @WithResource(name = "testproperties.properties", content = """
+ the.property=test
+ only.test=test
+ """)
void runWhenMultipleCustomNamesLoadsEachName() {
ConfigurableApplicationContext context = this.application
.run("--spring.config.name=moreproperties,testproperties");
- String property = context.getEnvironment().getProperty("the.property");
- assertThat(property).isEqualTo("frompropertiesfile");
+ assertThat(context.getEnvironment().getProperty("the.property")).isEqualTo("test");
+ assertThat(context.getEnvironment().getProperty("only.more")).isEqualTo("more");
+ assertThat(context.getEnvironment().getProperty("only.test")).isEqualTo("test");
}
@Test
+ @WithResource(name = "application-default.properties", content = "my.property=fromdefaultpropertiesfile")
void runWhenNoActiveProfilesLoadsDefaultProfileFile() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testprofiles");
+ ConfigurableApplicationContext context = this.application.run();
String property = context.getEnvironment().getProperty("my.property");
assertThat(property).isEqualTo("fromdefaultpropertiesfile");
}
@Test
+ @WithResource(name = "application.yaml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ other: notempty
+ ---
+ spring.config.activate.on-profile: default
+ my:
+ property: fromdefaultprofile
+ ---
+ spring.config.activate.on-profile: other
+ my:
+ property: fromotherprofile
+ """)
void runWhenActiveProfilesDoesNotLoadDefault() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testprofilesdocument",
- "--spring.config.location=classpath:configdata/profiles/", "--spring.profiles.default=thedefault",
- "--spring.profiles.active=other");
+ ConfigurableApplicationContext context = this.application.run("--spring.profiles.active=other");
String property = context.getEnvironment().getProperty("my.property");
assertThat(property).isEqualTo("fromotherprofile");
}
@Test
+ @WithResource(name = "application-thedefault.properties", content = "the.property=fromdefaultpropertiesfile")
void runWhenHasCustomDefaultProfileLoadsDefaultProfileFile() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testprofiles",
- "--spring.profiles.default=thedefault");
+ ConfigurableApplicationContext context = this.application.run("--spring.profiles.default=thedefault");
String property = context.getEnvironment().getProperty("the.property");
assertThat(property).isEqualTo("fromdefaultpropertiesfile");
}
@Test
+ @WithResource(name = "application.properties", content = """
+ foo=bucket
+ my.property=fromapplicationproperties
+ """)
+ @WithResource(name = "testproperties.properties", content = """
+ my.property=frompropertiesfile
+ the.property=frompropertiesfile
+ """)
void runWhenHasCustomSpringConfigLocationLoadsAllFromSpecifiedLocation() {
ConfigurableApplicationContext context = this.application
.run("--spring.config.location=classpath:application.properties,classpath:testproperties.properties");
@@ -187,29 +234,68 @@ void runWhenHasCustomSpringConfigLocationLoadsAllFromSpecifiedLocation() {
}
@Test
- void runWhenOneCustomLocationDoesNotExistLoadsOthers() {
+ @WithResource(name = "application.properties", content = """
+ foo=bucket
+ my.property=fromapplicationproperties
+ """)
+ @WithResource(name = "testproperties.properties", content = """
+ my.property=frompropertiesfile
+ the.property=frompropertiesfile
+ """)
+ void runWhenOneCustomOptionalLocationDoesNotExistLoadsOthers() {
ConfigurableApplicationContext context = this.application.run(
"--spring.config.location=classpath:application.properties,classpath:testproperties.properties,optional:classpath:nonexistent.properties");
- String property = context.getEnvironment().getProperty("the.property");
- assertThat(property).isEqualTo("frompropertiesfile");
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("frompropertiesfile");
+ assertThat(context.getEnvironment().getProperty("foo")).isEqualTo("bucket");
}
@Test
+ @WithResource(name = "application.yml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ ---
+ spring.config.activate.on-profile: prod
+ spring.config.import: file:./non-existent.yml
+ """)
void runWhenProfileSpecificMandatoryLocationDoesNotExistShouldNotFail() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testprofiles",
- "--spring.config.location=classpath:configdata/profiles/");
+ ConfigurableApplicationContext context = this.application.run();
String property = context.getEnvironment().getProperty("my.property");
assertThat(property).isEqualTo("fromyamlfile");
}
@Test
+ @WithResource(name = "application.yml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ ---
+ spring.config.activate.on-profile: prod
+ spring.config.import: file:./non-existent.yml
+ """)
void runWhenProfileSpecificMandatoryLocationDoesNotExistShouldFailWhenProfileActive() {
this.application.setAdditionalProfiles("prod");
- assertThatExceptionOfType(ConfigDataResourceNotFoundException.class).isThrownBy(() -> this.application
- .run("--spring.config.name=testprofiles", "--spring.config.location=classpath:configdata/profiles/"));
- }
-
- @Test
+ assertThatExceptionOfType(ConfigDataResourceNotFoundException.class).isThrownBy(() -> this.application.run())
+ .withMessageContaining("non-existent.yml");
+ }
+
+ @Test
+ @WithResource(name = "enableprofile.properties", content = """
+ spring.profiles.active=myprofile
+ my.property=frompropertiesfile
+ the.property=frompropertiesfile
+ one.more=${my.property}
+ """)
+ @WithResource(name = "enableother.properties", content = """
+ spring.profiles.active=other
+ my.property=fromenableotherpropertiesfile
+ one.more=${my.property}
+ """)
+ @WithResource(name = "enableprofile-other.properties", content = "other.property=fromotherpropertiesfile")
+ @WithResource(name = "enableprofile-myprofile.properties", content = """
+ my.property=fromprofilepropertiesfile
+ the.property=fromprofilepropertiesfile
+ """)
void runWhenHasActiveProfilesFromMultipleLocationsActivatesProfileFromOneLocation() {
ConfigurableApplicationContext context = this.application
.run("--spring.config.location=classpath:enableprofile.properties,classpath:enableother.properties");
@@ -220,13 +306,27 @@ void runWhenHasActiveProfilesFromMultipleLocationsActivatesProfileFromOneLocatio
}
@Test
+ @WithResource(name = "enableprofile.properties", content = """
+ spring.profiles.active=myprofile
+ my.property=frompropertiesfile
+ """)
+ @WithResource(name = "enabletwoprofiles.properties", content = """
+ spring.profiles.active=myprofile,another
+ my.property=fromtwopropertiesfile
+ """)
+ @WithResource(name = "enableprofile-myprofile.properties", content = """
+ my.property=frommyprofilepropertiesfile
+ """)
+ @WithResource(name = "enableprofile-another.properties", content = """
+ my.property=fromanotherprofilepropertiesfile
+ """)
void runWhenHasActiveProfilesFromMultipleAdditionalLocationsWithOneSwitchedOffLoadsExpectedProperties() {
ConfigurableApplicationContext context = this.application.run(
"--spring.config.additional-location=classpath:enabletwoprofiles.properties,classpath:enableprofile.properties");
ConfigurableEnvironment environment = context.getEnvironment();
assertThat(environment.getActiveProfiles()).containsExactly("myprofile");
String property = environment.getProperty("my.property");
- assertThat(property).isEqualTo("fromprofilepropertiesfile");
+ assertThat(property).isEqualTo("frommyprofilepropertiesfile");
}
@Test
@@ -249,14 +349,18 @@ void runWhenHasLocalFileLoadsWithLocalFileTakingPrecedenceOverClasspath() throws
}
@Test
+ @WithResource(name = "application.properties", content = """
+ my.property=frompropertiesfile
+ the.property=frompropertiesfile
+ """)
void runWhenHasCommandLinePropertiesLoadsWithCommandLineTakingPrecedence() {
StandardEnvironment environment = new StandardEnvironment();
environment.getPropertySources()
.addFirst(new SimpleCommandLinePropertySource("--the.property=fromcommandline"));
this.application.setEnvironment(environment);
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testproperties");
- String property = context.getEnvironment().getProperty("the.property");
- assertThat(property).isEqualTo("fromcommandline");
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("the.property")).isEqualTo("fromcommandline");
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("frompropertiesfile");
}
@Test
@@ -268,15 +372,17 @@ void runWhenHasSystemPropertyLoadsWithSystemPropertyTakingPrecedence() {
}
@Test
+ @WithResource(name = "application.properties", content = "my.property=fromapplicationproperties")
void runWhenHasDefaultPropertiesIncludesDefaultPropertiesLast() {
- this.application.setDefaultProperties(Collections.singletonMap("my.fallback", "foo"));
+ this.application.setDefaultProperties(Map.of("my.property", "fromdefaults", "my.fallback", "fromdefaults"));
ConfigurableApplicationContext context = this.application.run();
- String property = context.getEnvironment().getProperty("my.fallback");
- assertThat(property).isEqualTo("foo");
+ assertThat(context.getEnvironment().getProperty("my.fallback")).isEqualTo("fromdefaults");
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("fromapplicationproperties");
}
@Test
- void runWhenHasDefaultPropertiesWithConfigLocationConfigurationLoadsExpectedProperties() {
+ @WithResource(name = "testproperties.properties", content = "the.property=frompropertiesfile")
+ void runWhenHasDefaultPropertiesWithConfigNameLoadsExpectedProperties() {
this.application.setDefaultProperties(Collections.singletonMap("spring.config.name", "testproperties"));
ConfigurableApplicationContext context = this.application.run();
String property = context.getEnvironment().getProperty("the.property");
@@ -284,13 +390,15 @@ void runWhenHasDefaultPropertiesWithConfigLocationConfigurationLoadsExpectedProp
}
@Test
- void runWhenHasActiveProfilesFromDefaultPropertiesAndFileLoadsWithFileTakingPrecedence() {
+ @WithResource(name = "application.properties", content = "spring.profiles.active=myprofile")
+ void runWhenHasActiveProfilesFromDefaultPropertiesAndFileLoadsWithActiveProfilesFromFileTakingPrecedence() {
this.application.setDefaultProperties(Collections.singletonMap("spring.profiles.active", "dev"));
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=enableprofile");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getActiveProfiles()).containsExactly("myprofile");
}
@Test
+ @WithResource(name = "application-other.properties", content = "my.property=fromotherpropertiesfile")
void runWhenProgrammaticallySetProfilesLoadsWithSetProfilesTakePrecedenceOverDefaultProfile() {
this.application.setAdditionalProfiles("other");
ConfigurableApplicationContext context = this.application.run();
@@ -299,6 +407,8 @@ void runWhenProgrammaticallySetProfilesLoadsWithSetProfilesTakePrecedenceOverDef
}
@Test
+ @WithResource(name = "application-dev.properties", content = "my.property=fromdevpropertiesfile")
+ @WithResource(name = "application-other.properties", content = "my.property=fromotherpropertiesfile")
void runWhenTwoProfilesSetProgrammaticallyLoadsWithPreservedProfileOrder() {
this.application.setAdditionalProfiles("other", "dev");
ConfigurableApplicationContext context = this.application.run();
@@ -307,9 +417,12 @@ void runWhenTwoProfilesSetProgrammaticallyLoadsWithPreservedProfileOrder() {
}
@Test
+ @WithResource(name = "application.properties", content = "spring.profiles.active=myprofile")
+ @WithResource(name = "application-myprofile.properties", content = "the.property=fromprofilepropertiesfile")
+ @WithResource(name = "application-other.properties", content = "other.property=fromotherpropertiesfile")
void runWhenProfilesPresentBeforeConfigFileProcessingAugmentsProfileActivatedByConfigFile() {
this.application.setAdditionalProfiles("other");
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=enableprofile");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getActiveProfiles()).containsExactly("other", "myprofile");
String property = context.getEnvironment().getProperty("other.property");
assertThat(property).isEqualTo("fromotherpropertiesfile");
@@ -318,13 +431,19 @@ void runWhenProfilesPresentBeforeConfigFileProcessingAugmentsProfileActivatedByC
}
@Test
+ @WithResource(name = "application.properties", content = """
+ spring.profiles.active=myprofile
+ one.more=${my.property}
+ """)
+ @WithResource(name = "application-myprofile.properties", content = "my.property=fromprofilepropertiesfile")
void runWhenProfilePropertiesUsedInPlaceholdersLoadsWithResolvedPlaceholders() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=enableprofile");
- String property = context.getEnvironment().getProperty("one.more");
- assertThat(property).isEqualTo("fromprofilepropertiesfile");
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("one.more")).isEqualTo("fromprofilepropertiesfile");
}
@Test
+ @WithResource(name = "application-dev.properties", content = "my.property=fromdevpropertiesfile")
+ @WithResource(name = "application-other.properties", content = "my.property=fromotherpropertiesfile")
void runWhenDuplicateProfileSetProgrammaticallyAndViaPropertyLoadsWithProfiles() {
this.application.setAdditionalProfiles("dev");
ConfigurableApplicationContext context = this.application.run("--spring.profiles.active=dev,other");
@@ -333,6 +452,8 @@ void runWhenDuplicateProfileSetProgrammaticallyAndViaPropertyLoadsWithProfiles()
}
@Test
+ @WithResource(name = "application-dev.properties", content = "my.property=fromdevpropertiesfile")
+ @WithResource(name = "application-other.properties", content = "my.property=fromotherpropertiesfile")
void runWhenProfilesActivatedViaBracketNotationSetsProfiles() {
ConfigurableApplicationContext context = this.application.run("--spring.profiles.active[0]=dev",
"--spring.profiles.active[1]=other");
@@ -341,21 +462,43 @@ void runWhenProfilesActivatedViaBracketNotationSetsProfiles() {
}
@Test
+ @WithResource(name = "application.yaml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ other: notempty
+ ---
+ spring.config.activate.on-profile: dev
+ my:
+ property: fromdevprofile
+ """)
void loadWhenProfileInMultiDocumentFilesLoadsExpectedProperties() {
this.application.setAdditionalProfiles("dev");
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testprofiles",
- "--spring.config.location=classpath:configdata/profiles/");
- String property = context.getEnvironment().getProperty("my.property");
- assertThat(property).isEqualTo("fromdevprofile");
- property = context.getEnvironment().getProperty("my.other");
- assertThat(property).isEqualTo("notempty");
- }
-
- @Test
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevprofile");
+ assertThat(context.getEnvironment().getProperty("my.other")).isEqualTo("notempty");
+ }
+
+ @Test
+ @WithResource(name = "application.yaml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ other: notempty
+ ---
+ spring.config.activate.on-profile: dev
+ my:
+ property: fromdevprofile
+ dev:
+ property: devproperty
+ ---
+ spring.config.activate.on-profile: other
+ my:
+ property: fromotherprofile
+ """)
void runWhenMultipleActiveProfilesWithMultiDocumentFilesLoadsInOrderOfDocument() {
this.application.setAdditionalProfiles("other", "dev");
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testprofiles",
- "--spring.config.location=classpath:configdata/profiles/");
+ ConfigurableApplicationContext context = this.application.run();
String property = context.getEnvironment().getProperty("my.property");
assertThat(property).isEqualTo("fromotherprofile");
property = context.getEnvironment().getProperty("my.other");
@@ -365,106 +508,223 @@ void runWhenMultipleActiveProfilesWithMultiDocumentFilesLoadsInOrderOfDocument()
}
@Test
+ @WithResource(name = "application.yaml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ ---
+ spring.config.activate.on-profile: dev & other
+ my:
+ property: devandother
+ ---
+ spring.config.activate.on-profile: (dev | other) & another
+ my:
+ property: devorotherandanother
+ """)
void runWhenHasAndProfileExpressionLoadsExpectedProperties() {
- assertProfileExpression("devandother", "dev", "other");
- }
-
- @Test
+ this.application.setAdditionalProfiles("dev", "other");
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("devandother");
+ }
+
+ @Test
+ @WithResource(name = "application.yaml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ ---
+ spring.config.activate.on-profile: dev & other
+ my:
+ property: devandother
+ ---
+ spring.config.activate.on-profile: (dev | other) & another
+ my:
+ property: devorotherandanother
+ """)
void runWhenHasComplexProfileExpressionsLoadsExpectedProperties() {
- assertProfileExpression("devorotherandanother", "dev", "another");
- }
-
- @Test
+ this.application.setAdditionalProfiles("dev", "another");
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("devorotherandanother");
+ }
+
+ @Test
+ @WithResource(name = "application.yaml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ ---
+ spring.config.activate.on-profile: dev & other
+ my:
+ property: devandother
+ ---
+ spring.config.activate.on-profile: (dev | other) & another
+ my:
+ property: devorotherandanother
+ """)
void runWhenProfileExpressionsDoNotMatchLoadsExpectedProperties() {
- assertProfileExpression("fromyamlfile", "dev");
- }
-
- @Test
+ this.application.setAdditionalProfiles("dev");
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("fromyamlfile");
+ }
+
+ @Test
+ @WithResource(name = "application.yml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ other: notempty
+ ---
+ spring.config.activate.on-profile: other
+ my:
+ property: fromotherprofile
+ ---
+ spring.config.activate.on-profile: "!other"
+ my:
+ property: fromnototherprofile
+ notother: foo
+
+ """)
void runWhenHasNegatedProfilesLoadsExpectedProperties() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testnegatedprofiles",
- "--spring.config.location=classpath:configdata/profiles/");
- String property = context.getEnvironment().getProperty("my.property");
- assertThat(property).isEqualTo("fromnototherprofile");
- property = context.getEnvironment().getProperty("my.notother");
- assertThat(property).isEqualTo("foo");
- }
-
- @Test
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("fromnototherprofile");
+ assertThat(context.getEnvironment().getProperty("my.notother")).isEqualTo("foo");
+ }
+
+ @Test
+ @WithResource(name = "application.yml", content = """
+ ---
+ my:
+ property: fromyamlfile
+ other: notempty
+ ---
+ spring.config.activate.on-profile: other
+ my:
+ property: fromotherprofile
+ ---
+ spring.config.activate.on-profile: "!other"
+ my:
+ property: fromnototherprofile
+ notother: foo
+
+ """)
void runWhenHasNegatedProfilesWithProfileActiveLoadsExpectedProperties() {
this.application.setAdditionalProfiles("other");
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testnegatedprofiles",
- "--spring.config.location=classpath:configdata/profiles/");
- String property = context.getEnvironment().getProperty("my.property");
- assertThat(property).isEqualTo("fromotherprofile");
- property = context.getEnvironment().getProperty("my.notother");
- assertThat(property).isNull();
- }
-
- @Test
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("fromotherprofile");
+ assertThat(context.getEnvironment().getProperty("my.notother")).isNull();
+ }
+
+ @Test
+ @WithResource(name = "application.yml", content = """
+ ---
+ spring:
+ profiles:
+ active: dev
+ my:
+ property: fromyamlfile
+ ---
+ spring.config.activate.on-profile: dev
+ my:
+ property: fromdevprofile
+ """)
void runWhenHasActiveProfileConfigurationInMultiDocumentFileLoadsInExpectedOrder() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testsetprofiles",
- "--spring.config.location=classpath:configdata/profiles/");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getActiveProfiles()).containsExactly("dev");
String property = context.getEnvironment().getProperty("my.property");
assertThat(context.getEnvironment().getActiveProfiles()).contains("dev");
assertThat(property).isEqualTo("fromdevprofile");
assertThat(context.getEnvironment().getPropertySources()).extracting("name")
.contains(
- "Config resource 'class path resource [configdata/profiles/testsetprofiles.yml]' via location 'classpath:configdata/profiles/' (document #0)",
- "Config resource 'class path resource [configdata/profiles/testsetprofiles.yml]' via location 'classpath:configdata/profiles/' (document #1)");
+ "Config resource 'class path resource [application.yml]' via location 'optional:classpath:/' (document #0)",
+ "Config resource 'class path resource [application.yml]' via location 'optional:classpath:/' (document #1)");
}
@Test
+ @WithResource(name = "application.yml", content = """
+ ---
+ spring:
+ profiles:
+ active: dev,healthcheck
+ """)
void runWhenHasYamlWithCommaSeparatedMultipleProfilesLoadsExpectedProperties() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testsetmultiprofiles");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getActiveProfiles()).containsExactly("dev", "healthcheck");
}
@Test
+ @WithResource(name = "application.yml", content = """
+ ---
+ spring:
+ profiles:
+ active:
+ - dev
+ - healthcheck
+ """)
void runWhenHasYamlWithListProfilesLoadsExpectedProperties() {
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testsetmultiprofileslist");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getActiveProfiles()).containsExactly("dev", "healthcheck");
}
@Test
+ @WithResource(name = "application.yml", content = """
+ ---
+ spring:
+ profiles:
+ active: dev , healthcheck
+ """)
void loadWhenHasWhitespaceTrims() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.name=testsetmultiprofileswhitespace");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getActiveProfiles()).containsExactly("dev", "healthcheck");
}
@Test
- void loadWhenHasConfigLocationAsFile() {
- String location = "file:src/test/resources/specificlocation.properties";
+ void loadWhenHasConfigLocationAsFile() throws IOException {
+ File properties = new File(this.temp, "specificlocation.properties");
+ Files.write(properties.toPath(),
+ List.of("my.property=fromspecificlocation", "the.property=fromspecificlocation"));
+ String location = properties.toURI().toURL().toString();
ConfigurableApplicationContext context = this.application.run("--spring.config.location=" + location);
- assertThat(context.getEnvironment()).has(matchingPropertySource("Config resource 'file [" + Strings
- .join(Arrays.asList("src", "test", "resources", "specificlocation.properties"), File.separatorChar)
- + "]' via location '" + location + "'"));
+ assertThat(context.getEnvironment())
+ .has(matchingPropertySource("Config resource 'file [" + properties + "]' via location '" + location + "'"));
}
@Test
- void loadWhenHasRelativeConfigLocationUsesFileLocation() {
- String location = "src/test/resources/specificlocation.properties";
- ConfigurableApplicationContext context = this.application.run("--spring.config.location=" + location);
- assertThat(context.getEnvironment()).has(matchingPropertySource("Config resource 'file [" + Strings
- .join(Arrays.asList("src", "test", "resources", "specificlocation.properties"), File.separatorChar)
- + "]' via location '" + location + "'"));
+ void loadWhenHasRelativeConfigLocationUsesFileLocation() throws IOException {
+ File buildOutput = new BuildOutput(getClass()).getRootLocation();
+ File resources = new File(buildOutput, "resources-" + UUID.randomUUID());
+ try {
+ resources.mkdirs();
+ File properties = new File(resources, "specificlocation.properties").getAbsoluteFile();
+ Files.write(properties.toPath(),
+ List.of("my.property=fromspecificlocation", "the.property=fromspecificlocation"));
+ Path relative = new File("").getAbsoluteFile().toPath().relativize(properties.toPath());
+ ConfigurableApplicationContext context = this.application.run("--spring.config.location=" + relative);
+ assertThat(context.getEnvironment()).has(matchingPropertySource(
+ "Config resource 'file [" + relative + "]' via location '" + relative + "'"));
+ }
+ finally {
+ FileSystemUtils.deleteRecursively(resources);
+ }
}
@Test
+ @WithResource(name = "application-customdefault.properties", content = "customdefault=true")
+ @WithResource(name = "application-dev.properties", content = "my.property=fromdevpropertiesfile")
void loadWhenCustomDefaultProfileAndActiveFromPreviousSourceDoesNotActivateDefault() {
ConfigurableApplicationContext context = this.application.run("--spring.profiles.default=customdefault",
"--spring.profiles.active=dev");
- String property = context.getEnvironment().getProperty("my.property");
- assertThat(property).isEqualTo("fromdevpropertiesfile");
+ assertThat(context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
assertThat(context.getEnvironment().containsProperty("customdefault")).isFalse();
}
@Test
+ @WithResource(name = "application.properties", content = """
+ spring.profiles.active=customdefault
+ customprofile=true
+ """)
+ @WithResource(name = "application-customdefault.properties", content = "customprofile-customdefault=true")
void runWhenCustomDefaultProfileSameAsActiveFromFileActivatesProfile() {
- ConfigurableApplicationContext context = this.application.run(
- "--spring.config.location=classpath:configdata/profiles/", "--spring.profiles.default=customdefault",
- "--spring.config.name=customprofile");
+ ConfigurableApplicationContext context = this.application.run("--spring.profiles.default=customdefault");
ConfigurableEnvironment environment = context.getEnvironment();
assertThat(environment.containsProperty("customprofile")).isTrue();
assertThat(environment.containsProperty("customprofile-customdefault")).isTrue();
@@ -472,13 +732,18 @@ void runWhenCustomDefaultProfileSameAsActiveFromFileActivatesProfile() {
}
@Test
+ @WithResource(name = "application.properties", content = "spring.profiles.active=${activeProfile:propertiesfile}")
void runWhenActiveProfilesCanBeConfiguredUsingPlaceholdersResolvedAgainstTheEnvironmentLoadsExpectedProperties() {
- ConfigurableApplicationContext context = this.application.run("--activeProfile=testPropertySource",
- "--spring.config.name=testactiveprofiles");
+ ConfigurableApplicationContext context = this.application.run("--activeProfile=testPropertySource");
assertThat(context.getEnvironment().getActiveProfiles()).containsExactly("testPropertySource");
}
@Test
+ @WithResource(name = "application.properties", content = """
+ foo=bucket
+ value=1234
+ """)
+ @WithResource(name = "override.properties", content = "foo=bar")
void runWhenHasAdditionalLocationLoadsWithAdditionalTakingPrecedenceOverDefaultLocation() {
ConfigurableApplicationContext context = this.application
.run("--spring.config.additional-location=classpath:override.properties");
@@ -487,6 +752,12 @@ void runWhenHasAdditionalLocationLoadsWithAdditionalTakingPrecedenceOverDefaultL
}
@Test
+ @WithResource(name = "application.properties", content = """
+ foo=bucket
+ value=1234
+ """)
+ @WithResource(name = "override.properties", content = "foo=bar")
+ @WithResource(name = "some.properties", content = "foo=spam")
void runWhenMultipleAdditionalLocationsLoadsWithLastWinning() {
ConfigurableApplicationContext context = this.application
.run("--spring.config.additional-location=classpath:override.properties,classpath:some.properties");
@@ -495,6 +766,9 @@ void runWhenMultipleAdditionalLocationsLoadsWithLastWinning() {
}
@Test
+ @WithResource(name = "application.properties", content = "value=1234")
+ @WithResource(name = "override.properties", content = "foo=bar")
+ @WithResource(name = "some.properties", content = "foo=spam")
void runWhenAdditionalLocationAndLocationLoadsWithAdditionalTakingPrecedenceOverConfigured() {
ConfigurableApplicationContext context = this.application.run(
"--spring.config.location=classpath:some.properties",
@@ -504,12 +778,19 @@ void runWhenAdditionalLocationAndLocationLoadsWithAdditionalTakingPrecedenceOver
}
@Test
+ @WithResource(name = "application.custom", content = "")
+ @WithResource(name = "META-INF/spring.factories", content = """
+ org.springframework.boot.env.PropertySourceLoader=\
+ org.springframework.boot.context.config.TestPropertySourceLoader1,\
+ org.springframework.boot.context.config.TestPropertySourceLoader2
+ """)
void runWhenPropertiesFromCustomPropertySourceLoaderShouldLoadFromCustomSource() {
ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getProperty("customloader1")).isEqualTo("true");
}
@Test
+ @WithResource(name = "gh17001.properties", content = "gh17001loaded=true")
void runWhenCustomDefaultPropertySourceLoadsWithoutReplacingCustomSource() {
// gh-17011
Map source = new HashMap<>();
@@ -581,75 +862,123 @@ void runWhenConfigLocationHasMandatoryDirectoryThatDoesntExistThrowsException()
void runWhenConfigLocationHasNonOptionalEmptyFileDoesNotThrowException() throws IOException {
File location = new File(this.temp, "application.properties");
FileCopyUtils.copy(new byte[0], location);
- assertThatNoException()
- .isThrownBy(() -> this.application.run("--spring.config.location=classpath:/application.properties,"
- + StringUtils.cleanPath(location.getAbsolutePath())));
+ assertThatNoException().isThrownBy(() -> this.application
+ .run("--spring.config.location=" + StringUtils.cleanPath(location.getAbsolutePath())));
}
@Test
+ @WithResource(name = "META-INF/spring.factories", content = """
+ org.springframework.boot.context.config.ConfigDataLocationResolver=\
+ org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests$LocationResolver
+
+ org.springframework.boot.context.config.ConfigDataLoader=\
+ org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests$Loader
+ """)
void runWhenResolvedIsOptionalDoesNotThrowException() {
ApplicationContext context = this.application.run("--spring.config.location=test:optionalresult");
assertThat(context.getEnvironment().containsProperty("spring")).isFalse();
}
@Test
+ @WithResource(name = "application.properties", content = "spring.profiles=a")
void runWhenUsingInvalidPropertyThrowsException() {
- assertThatExceptionOfType(InvalidConfigDataPropertyException.class)
- .isThrownBy(() -> this.application.run("--spring.config.location=classpath:invalidproperty.properties"));
+ assertThatExceptionOfType(InvalidConfigDataPropertyException.class).isThrownBy(() -> this.application.run());
}
@Test
+ @WithResource(name = "application.properties", content = """
+ my.import=imported
+ spring.config.import=classpath:${my.import}.properties
+ """)
+ @WithResource(name = "imported.properties", content = "my.value=iwasimported")
void runWhenImportUsesPlaceholder() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.location=classpath:application-import-with-placeholder.properties");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getProperty("my.value")).isEqualTo("iwasimported");
}
@Test
+ @WithResource(name = "application.properties", content = """
+ my.import=imported
+ #---
+ spring.config.import=classpath:${my.import}.properties
+ """)
+ @WithResource(name = "imported.properties", content = "my.value=iwasimported")
void runWhenImportFromEarlierDocumentUsesPlaceholder() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.location=classpath:application-import-with-placeholder-in-document.properties");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getProperty("my.value")).isEqualTo("iwasimported");
}
@Test // gh-26858
+ @WithResource(name = "application.properties", content = """
+ spring.config.import=classpath:imported.properties
+ my.value=application.properties
+ """)
+ @WithResource(name = "imported.properties", content = "my.value=imported.properties")
+ @WithResource(name = "application-dev.properties", content = "my.value=application-dev.properties")
void runWhenImportWithProfileVariantOrdersPropertySourcesCorrectly() {
this.application.setAdditionalProfiles("dev");
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.location=classpath:application-import-with-profile-variant.properties");
- assertThat(context.getEnvironment().getProperty("my.value"))
- .isEqualTo("application-import-with-profile-variant-imported-dev");
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("my.value")).isEqualTo("application-dev.properties");
}
@Test
+ @WithResource(name = "application.properties", content = """
+ spring.config.import=classpath:imported.properties
+ my.value=application.properties
+ """)
+ @WithResource(name = "imported.properties", content = "my.value=imported.properties")
+ @WithResource(name = "imported-dev.properties", content = "my.value=imported-dev.properties")
+ @WithResource(name = "application-dev.properties", content = """
+ spring.config.import=imported-dev.properties
+ my.value=application-dev.properties""")
void runWhenImportWithProfileVariantAndDirectProfileImportOrdersPropertySourcesCorrectly() {
this.application.setAdditionalProfiles("dev");
- ConfigurableApplicationContext context = this.application.run(
- "--spring.config.location=classpath:application-import-with-profile-variant-and-direct-profile-import.properties");
- assertThat(context.getEnvironment().getProperty("my.value"))
- .isEqualTo("application-import-with-profile-variant-imported-dev");
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("my.value")).isEqualTo("imported-dev.properties");
}
@Test
+ @WithResource(name = "application.properties", content = """
+ my.import=application-import-with-placeholder-imported
+ #---
+ spring.config.import=classpath:org/springframework/boot/context/config/${my.import}.properties
+ #---
+ my.import=badbadbad
+ spring.config.activate.on-profile=missing
+ """)
void runWhenHasPropertyInProfileDocumentThrowsException() {
- assertThatExceptionOfType(BindException.class).isThrownBy(() -> this.application.run(
- "--spring.config.location=classpath:application-import-with-placeholder-in-profile-document.properties"))
+ assertThatExceptionOfType(BindException.class).isThrownBy(() -> this.application.run())
.withCauseInstanceOf(InactiveConfigDataAccessException.class);
}
@Test // gh-29386
+ @WithResource(name = "application.properties", content = """
+ my.value=application
+ #---
+ my.import=imported
+ spring.config.activate.on-profile=missing
+ #---
+ spring.config.import=${my.import}.properties
+ """)
+ @WithResource(name = "imported.properties", content = "my.value=imported")
void runWhenHasPropertyInEarlierProfileDocumentThrowsException() {
- assertThatExceptionOfType(BindException.class).isThrownBy(() -> this.application.run(
- "--spring.config.location=classpath:application-import-with-placeholder-in-earlier-profile-document.properties"))
+ assertThatExceptionOfType(BindException.class).isThrownBy(() -> this.application.run())
.withCauseInstanceOf(InactiveConfigDataAccessException.class);
}
@Test // gh-29386
+ @WithResource(name = "application.properties", content = """
+ my.import=imported
+ #---
+ my.value=should-be-ignored
+ spring.config.activate.on-profile=missing
+ #---
+ spring.config.import=classpath:${my.import}.properties
+ """)
+ @WithResource(name = "imported.properties", content = "my.value=imported")
void runWhenHasPropertyInEarlierDocumentLoads() {
- ConfigurableApplicationContext context = this.application.run(
- "--spring.config.location=classpath:application-import-with-placeholder-in-earlier-document.properties");
- assertThat(context.getEnvironment().getProperty("my.value"))
- .isEqualTo("application-import-with-placeholder-in-earlier-document-imported");
+ ConfigurableApplicationContext context = this.application.run();
+ assertThat(context.getEnvironment().getProperty("my.value")).isEqualTo("imported");
}
@Test
@@ -665,38 +994,69 @@ void runWhenHasNonOptionalImportAndIgnoreNotFoundPropertyDoesNotThrowException()
}
@Test
+ @WithResource(name = "application.properties", content = """
+ spring.profiles.active=p1
+ spring.profiles.include=p2
+ #---
+ spring.profiles.include=p3,p4
+ #---
+ spring.profiles.include=p5
+ """)
void runWhenHasIncludedProfilesActivatesProfiles() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.location=classpath:application-include-profiles.properties");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getActiveProfiles()).containsExactlyInAnyOrder("p1", "p2", "p3", "p4",
"p5");
}
@Test
+ @WithResource(name = "application.properties", content = """
+ spring.profiles.active=p1
+ spring.profiles.include=p2
+ #---
+ myprofile=p4
+ spring.profiles.include=p3,${myprofile}
+ #---
+ myotherprofile=p5
+ spring.profiles.include=${myotherprofile}
+ """)
void runWhenHasIncludedProfilesWithPlaceholderActivatesProfiles() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.location=classpath:application-include-profiles-with-placeholder.properties");
+ ConfigurableApplicationContext context = this.application.run();
assertThat(context.getEnvironment().getActiveProfiles()).containsExactlyInAnyOrder("p1", "p2", "p3", "p4",
"p5");
}
@Test
+ @WithResource(name = "application.properties", content = """
+ spring.profiles.active=p1
+ spring.profiles.include=p2
+ #---
+ spring.config.activate.on-profile=p2
+ spring.profiles.include=p3
+ """)
void runWhenHasIncludedProfilesWithProfileSpecificDocumentThrowsException() {
- assertThatExceptionOfType(InactiveConfigDataAccessException.class).isThrownBy(() -> this.application.run(
- "--spring.config.location=classpath:application-include-profiles-in-profile-specific-document.properties"));
+ assertThatExceptionOfType(InactiveConfigDataAccessException.class).isThrownBy(() -> this.application.run());
}
@Test
+ @WithResource(name = "application-test.yaml", content = """
+ spring:
+ profiles:
+ include:
+ - p
+ """)
void runWhenHasIncludedProfilesWithListSyntaxWithProfileSpecificDocumentThrowsException() {
- assertThatExceptionOfType(InvalidConfigDataPropertyException.class).isThrownBy(() -> this.application.run(
- "--spring.config.name=application-include-profiles-list-in-profile-specific-file",
- "--spring.profiles.active=test"));
+ assertThatExceptionOfType(InvalidConfigDataPropertyException.class)
+ .isThrownBy(() -> this.application.run("--spring.profiles.active=test"));
}
@Test
+ @WithResource(name = "application.properties", content = """
+ my.import=imported
+ spring.config.import=classpath:${my.import}.properties
+ """)
+ @WithResource(name = "imported.properties", content = "my.value=imported")
void runWhenImportingIncludesParentOrigin() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.location=classpath:application-import-with-placeholder.properties");
+ ConfigurableApplicationContext context = this.application.run();
Binder binder = Binder.get(context.getEnvironment());
List properties = new ArrayList<>();
BindHandler bindHandler = new BindHandler() {
@@ -712,107 +1072,158 @@ public Object onSuccess(ConfigurationPropertyName name, Bindable> target, Bind
binder.bind("my.value", Bindable.of(String.class), bindHandler);
assertThat(properties).hasSize(1);
Origin origin = properties.get(0).getOrigin();
- assertThat(origin.toString()).contains("application-import-with-placeholder-imported");
- assertThat(origin.getParent().toString()).contains("application-import-with-placeholder");
+ assertThat(origin.toString()).contains("imported.properties");
+ assertThat(origin.getParent().toString()).contains("application.properties");
}
@Test
+ @WithResource(name = "config/first/application.properties", content = "first.property=apple")
+ @WithResource(name = "config/second/application.properties", content = "second.property=ball")
+ @WithResource(name = "config/third/nested/application.properties", content = "third.property=three")
void runWhenHasWildcardLocationLoadsFromAllMatchingLocations() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.location=file:src/test/resources/config/*/", "--spring.config.name=testproperties");
+ ConfigurableApplicationContext context = this.application.run("--spring.config.location=classpath:config/*/");
ConfigurableEnvironment environment = context.getEnvironment();
assertThat(environment.getProperty("first.property")).isEqualTo("apple");
assertThat(environment.getProperty("second.property")).isEqualTo("ball");
+ assertThat(environment.getProperty("third.property")).isNull();
}
@Test
- void runWhenOptionalWildcardLocationDoesNotExistDoesNotThrowException() {
+ void runWhenOptionalWildcardFileDoesNotExistDoesNotThrowException() {
assertThatNoException().isThrownBy(() -> this.application
- .run("--spring.config.location=optional:file:src/test/resources/nonexistent/*/testproperties.properties"));
+ .run("--spring.config.location=optional:classpath:nonexistent/*/testproperties.properties"));
}
@Test
- void runWhenMandatoryWildcardLocationDoesNotExistThrowsException() {
+ void runWhenMandatoryWildcardFileDoesNotExistThrowsException() {
assertThatExceptionOfType(ConfigDataLocationNotFoundException.class).isThrownBy(() -> this.application
- .run("--spring.config.location=file:src/test/resources/nonexistent/*/testproperties.properties"));
+ .run("--spring.config.location=classpath:nonexistent/*/testproperties.properties"));
}
@Test
- void runWhenMandatoryWildcardLocationHasEmptyFileDirectory() {
- assertThatNoException()
- .isThrownBy(() -> this.application.run("--spring.config.location=file:src/test/resources/config/*/"));
+ @WithResourceDirectory("config/empty")
+ void runWhenMandatoryWildcardDirectoryHasEmptyDirectoryDoesNotThrowException() {
+ assertThatNoException().isThrownBy(() -> this.application.run("--spring.config.location=classpath:config/*/"));
}
@Test
- void runWhenMandatoryWildcardLocationHasNoSubdirectories() {
- assertThatExceptionOfType(ConfigDataLocationNotFoundException.class)
- .isThrownBy(
- () -> this.application.run("--spring.config.location=file:src/test/resources/config/0-empty/*/"))
- .withMessage("Config data location 'file:src/test/resources/config/0-empty/*/' contains no subdirectories");
+ @WithResourceDirectory("config/empty")
+ void runWhenOptionalWildcardDirectoryHasNoSubdirectoriesDoesNotThrow() {
+ assertThatNoException()
+ .isThrownBy(() -> this.application.run("--spring.config.location=optional:classpath:config/*/"));
}
@Test
- void runWhenHasMandatoryWildcardLocationThatDoesNotExist() {
+ @WithResourceDirectory("config")
+ void runWhenMandatoryWildcardDirectoryHasNoSubdirectoriesThrows() {
assertThatExceptionOfType(ConfigDataLocationNotFoundException.class)
- .isThrownBy(() -> this.application.run("--spring.config.location=file:invalid/*/"));
+ .isThrownBy(() -> this.application.run("--spring.config.location=classpath:config/*/"))
+ .withMessage("Config data location 'classpath:config/*/' contains no subdirectories");
}
@Test
- void runWhenHasOptionalWildcardLocationThatDoesNotExistDoesNotThrow() {
+ void runWhenOptionalWildcardDirectoryDoesNotExistDoesNotThrowException() {
assertThatNoException()
.isThrownBy(() -> this.application.run("--spring.config.location=optional:file:invalid/*/"));
}
- @Test
- void runWhenOptionalWildcardLocationHasNoSubdirectoriesDoesNotThrow() {
- assertThatNoException().isThrownBy(() -> this.application
- .run("--spring.config.location=optional:file:src/test/resources/config/0-empty/*/"));
- }
-
@Test // gh-24990
+ @WithResource(name = "application.properties", content = "spring.profiles.active=test,other")
+ @WithResource(name = "application-test.properties", content = """
+ test1=test1
+ #---
+ spring.config.activate.on-profile=other
+ test2=test2
+ """)
void runWhenHasProfileSpecificFileWithActiveOnProfileProperty() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.name=application-activate-on-profile-in-profile-specific-file");
+ ConfigurableApplicationContext context = this.application.run();
ConfigurableEnvironment environment = context.getEnvironment();
assertThat(environment.getProperty("test1")).isEqualTo("test1");
assertThat(environment.getProperty("test2")).isEqualTo("test2");
}
@Test // gh-26960
+ @WithResource(name = "application.properties", content = """
+ spring.profiles.active=p1,p2
+ application=true
+ """)
+ @WithResource(name = "application-p1.properties", content = """
+ application-p1=true
+ spring.config.import=import.properties
+ """)
+ @WithResource(name = "import.properties", content = "import=true")
+ @WithResource(name = "import-p1.properties", content = "import-p1=true")
+ @WithResource(name = "import-p2.properties", content = "import-p2=true")
void runWhenHasProfileSpecificImportWithImportImportsSecondProfileSpecificFile() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.name=application-profile-specific-import-with-import");
+ ConfigurableApplicationContext context = this.application.run();
ConfigurableEnvironment environment = context.getEnvironment();
- assertThat(environment.containsProperty("application-profile-specific-import-with-import")).isTrue();
- assertThat(environment.containsProperty("application-profile-specific-import-with-import-p1")).isTrue();
- assertThat(environment.containsProperty("application-profile-specific-import-with-import-p2")).isFalse();
- assertThat(environment.containsProperty("application-profile-specific-import-with-import-import")).isTrue();
- assertThat(environment.containsProperty("application-profile-specific-import-with-import-import-p1")).isTrue();
- assertThat(environment.containsProperty("application-profile-specific-import-with-import-import-p2")).isTrue();
+ assertThat(environment.containsProperty("application")).isTrue();
+ assertThat(environment.containsProperty("application-p1")).isTrue();
+ assertThat(environment.containsProperty("application-p2")).isFalse();
+ assertThat(environment.containsProperty("import")).isTrue();
+ assertThat(environment.containsProperty("import-p1")).isTrue();
+ assertThat(environment.containsProperty("import-p2")).isTrue();
}
@Test // gh-26960
+ @WithResource(name = "application.properties", content = "spring.profiles.active=p1,p2")
+ @WithResource(name = "application-p1.properties", content = "spring.config.import:test:boot")
+ @WithResource(name = "META-INF/spring.factories", content = """
+ org.springframework.boot.context.config.ConfigDataLocationResolver=\
+ org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests$LocationResolver
+
+ org.springframework.boot.context.config.ConfigDataLoader=\
+ org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests$Loader
+ """)
void runWhenHasProfileSpecificImportWithCustomImportResolvesProfileSpecific() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.name=application-profile-specific-import-with-custom-import");
+ ConfigurableApplicationContext context = this.application.run();
ConfigurableEnvironment environment = context.getEnvironment();
assertThat(environment.containsProperty("test:boot")).isTrue();
assertThat(environment.containsProperty("test:boot:ps")).isTrue();
}
@Test // gh-26593
+ @WithResource(name = "application.properties", content = """
+ root=true
+ v1=root
+ v2=root
+ """)
+ @WithResource(name = "application-p1.properties", content = """
+ root-p1=true
+ v1=root-p1
+ v2=root-p1
+ """)
+ @WithResource(name = "application-p2.properties", content = """
+ root-p2=true
+ v1=root-p2
+ v2=root-p2
+ """)
+ @WithResource(name = "config/application.properties", content = """
+ config=true
+ v1=config
+ v2=config
+ """)
+ @WithResource(name = "config/application-p1.properties", content = """
+ config-p1=true
+ v1=config-p1
+ #v2 intentionally missing
+ """)
+ @WithResource(name = "config/application-p2.properties", content = """
+ config-p2=true
+ v1=config-p2
+ #v2 intentionally missing
+ """)
void runWhenHasFilesInRootAndConfigWithProfiles() {
- ConfigurableApplicationContext context = this.application
- .run("--spring.config.name=file-in-root-and-config-with-profile", "--spring.profiles.active=p1,p2");
+ ConfigurableApplicationContext context = this.application.run("--spring.profiles.active=p1,p2");
ConfigurableEnvironment environment = context.getEnvironment();
- assertThat(environment.containsProperty("file-in-root-and-config-with-profile")).isTrue();
- assertThat(environment.containsProperty("file-in-root-and-config-with-profile-p1")).isTrue();
- assertThat(environment.containsProperty("file-in-root-and-config-with-profile-p2")).isTrue();
- assertThat(environment.containsProperty("config-file-in-root-and-config-with-profile")).isTrue();
- assertThat(environment.containsProperty("config-file-in-root-and-config-with-profile-p1")).isTrue();
- assertThat(environment.containsProperty("config-file-in-root-and-config-with-profile-p2")).isTrue();
- assertThat(environment.getProperty("v1")).isEqualTo("config-file-in-root-and-config-with-profile-p2");
- assertThat(environment.getProperty("v2")).isEqualTo("file-in-root-and-config-with-profile-p2");
+ assertThat(environment.containsProperty("root")).isTrue();
+ assertThat(environment.containsProperty("root-p1")).isTrue();
+ assertThat(environment.containsProperty("root-p2")).isTrue();
+ assertThat(environment.containsProperty("config")).isTrue();
+ assertThat(environment.containsProperty("config-p1")).isTrue();
+ assertThat(environment.containsProperty("config-p2")).isTrue();
+ assertThat(environment.getProperty("v1")).isEqualTo("config-p2");
+ assertThat(environment.getProperty("v2")).isEqualTo("root-p2");
}
private Condition matchingPropertySource(final String sourceName) {
@@ -820,21 +1231,12 @@ private Condition matchingPropertySource(final String s
@Override
public boolean matches(ConfigurableEnvironment value) {
- value.getPropertySources().forEach((ps) -> System.out.println(ps.getName()));
return value.getPropertySources().contains(sourceName);
}
};
}
- private void assertProfileExpression(String value, String... activeProfiles) {
- this.application.setAdditionalProfiles(activeProfiles);
- ConfigurableApplicationContext context = this.application.run("--spring.config.name=testprofileexpression",
- "--spring.config.location=classpath:configdata/profiles/");
- String property = context.getEnvironment().getProperty("my.property");
- assertThat(property).isEqualTo(value);
- }
-
@Configuration(proxyBeanMethods = false)
static class Config {
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java
index f7139ad750ad..283b3be3a87d 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -27,6 +27,7 @@
import org.springframework.boot.DefaultBootstrapContext;
import org.springframework.boot.SpringApplication;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
@@ -103,6 +104,8 @@ void postProcessEnvironmentWhenNoActiveProfiles() {
}
@Test
+ @WithResource(name = "application.properties", content = "property=value")
+ @WithResource(name = "application-dev.properties", content = "property=dev-value")
void applyToAppliesPostProcessing() {
int before = this.environment.getPropertySources().size();
TestConfigDataEnvironmentUpdateListener listener = new TestConfigDataEnvironmentUpdateListener();
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentTests.java
index d602bf215444..656e93c2670b 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -16,7 +16,6 @@
package org.springframework.boot.context.config;
-import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
@@ -28,7 +27,6 @@
import java.util.function.Supplier;
import org.assertj.core.api.InstanceOfAssertFactories;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.params.ParameterizedTest;
@@ -42,6 +40,7 @@
import org.springframework.boot.context.config.TestConfigDataEnvironmentUpdateListener.AddedPropertySource;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.logging.DeferredLogFactory;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -149,8 +148,8 @@ void createCreatesInitialImportContributorsInCorrectOrder() {
}
@Test
- void processAndApplyAddsImportedSourceToEnvironment(TestInfo info) {
- this.environment.setProperty("spring.config.location", getConfigLocation(info));
+ @WithResource(name = "application.properties", content = "spring=boot")
+ void processAndApplyAddsImportedSourceToEnvironment() {
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, null);
configDataEnvironment.processAndApply();
@@ -158,8 +157,14 @@ void processAndApplyAddsImportedSourceToEnvironment(TestInfo info) {
}
@Test
- void processAndApplyOnlyAddsActiveContributors(TestInfo info) {
- this.environment.setProperty("spring.config.location", getConfigLocation(info));
+ @WithResource(name = "application.properties", content = """
+ spring=boot
+ #---
+ spring.config.activate.on-profile=missing
+ other=value
+ No newline at end of file
+ """)
+ void processAndApplyOnlyAddsActiveContributors() {
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, null);
configDataEnvironment.processAndApply();
@@ -180,8 +185,8 @@ void processAndApplyMovesDefaultPropertySourceToLast(TestInfo info) {
}
@Test
+ @WithResource(name = "application.properties", content = "spring.profiles.default=one,two,three")
void processAndApplySetsDefaultProfiles(TestInfo info) {
- this.environment.setProperty("spring.config.location", getConfigLocation(info));
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, null);
configDataEnvironment.processAndApply();
@@ -189,8 +194,8 @@ void processAndApplySetsDefaultProfiles(TestInfo info) {
}
@Test
- void processAndApplySetsActiveProfiles(TestInfo info) {
- this.environment.setProperty("spring.config.location", getConfigLocation(info));
+ @WithResource(name = "application.properties", content = "spring.profiles.active=one,two,three")
+ void processAndApplySetsActiveProfiles() {
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, null);
configDataEnvironment.processAndApply();
@@ -198,8 +203,11 @@ void processAndApplySetsActiveProfiles(TestInfo info) {
}
@Test
- void processAndApplySetsActiveProfilesAndProfileGroups(TestInfo info) {
- this.environment.setProperty("spring.config.location", getConfigLocation(info));
+ @WithResource(name = "application.properties", content = """
+ spring.profiles.active=one,two,three
+ spring.profiles.group.one=four,five
+ """)
+ void processAndApplySetsActiveProfilesAndProfileGroups() {
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, null);
configDataEnvironment.processAndApply();
@@ -207,8 +215,8 @@ void processAndApplySetsActiveProfilesAndProfileGroups(TestInfo info) {
}
@Test
+ @WithResource(name = "application.properties", content = "spring.profiles.active=test")
void processAndApplyDoesNotSetProfilesFromIgnoreProfilesContributors(TestInfo info) {
- this.environment.setProperty("spring.config.location", getConfigLocation(info));
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, null) {
@@ -281,8 +289,8 @@ protected ConfigDataEnvironmentContributors createContributors(
}
@Test
+ @WithResource(name = "application.properties", content = "spring=boot")
void processAndApplyDoesNotSetProfilesFromIgnoreProfilesContributorsWhenNoProfilesActive(TestInfo info) {
- this.environment.setProperty("spring.config.location", getConfigLocation(info));
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, null) {
@@ -307,9 +315,8 @@ protected ConfigDataEnvironmentContributors createContributors(
}
@Test
- @Disabled("Disabled until spring.profiles support is dropped")
void processAndApplyWhenHasInvalidPropertyThrowsException() {
- this.environment.setProperty("spring.profile", "a");
+ this.environment.setProperty("spring.profiles", "a");
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, null);
assertThatExceptionOfType(InvalidConfigDataPropertyException.class)
@@ -317,8 +324,9 @@ void processAndApplyWhenHasInvalidPropertyThrowsException() {
}
@Test
+ @WithResource(name = "custom/config.properties", content = "spring=boot")
void processAndApplyWhenHasListenerCallsOnPropertySourceAdded(TestInfo info) {
- this.environment.setProperty("spring.config.location", getConfigLocation(info));
+ this.environment.setProperty("spring.config.location", "classpath:custom/config.properties");
TestConfigDataEnvironmentUpdateListener listener = new TestConfigDataEnvironmentUpdateListener();
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, listener);
@@ -326,14 +334,14 @@ void processAndApplyWhenHasListenerCallsOnPropertySourceAdded(TestInfo info) {
assertThat(listener.getAddedPropertySources()).hasSize(1);
AddedPropertySource addedPropertySource = listener.getAddedPropertySources().get(0);
assertThat(addedPropertySource.getPropertySource().getProperty("spring")).isEqualTo("boot");
- assertThat(addedPropertySource.getLocation()).hasToString(getConfigLocation(info));
+ assertThat(addedPropertySource.getLocation()).hasToString("classpath:custom/config.properties");
assertThat(addedPropertySource.getResource().toString()).contains("class path resource")
- .contains(info.getTestMethod().get().getName());
+ .contains("custom/config.properties");
}
@Test
+ @WithResource(name = "application.properties", content = "spring.profiles.active=one,two,three")
void processAndApplyWhenHasListenerCallsOnSetProfiles(TestInfo info) {
- this.environment.setProperty("spring.config.location", getConfigLocation(info));
TestConfigDataEnvironmentUpdateListener listener = new TestConfigDataEnvironmentUpdateListener();
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, listener);
@@ -343,17 +351,18 @@ void processAndApplyWhenHasListenerCallsOnSetProfiles(TestInfo info) {
@Test
@SuppressWarnings("rawtypes")
+ @WithResource(name = "separate-class-loader-spring.factories", content = """
+ org.springframework.boot.context.config.ConfigDataLoader=\
+ org.springframework.boot.context.config.ConfigDataEnvironmentTests$SeparateClassLoaderConfigDataLoader
+ """)
void configDataLoadersAreLoadedUsingClassLoaderFromResourceLoader() {
ResourceLoader resourceLoader = mock(ResourceLoader.class);
- ClassLoader classLoader = new ClassLoader() {
+ ClassLoader classLoader = new ClassLoader(Thread.currentThread().getContextClassLoader()) {
@Override
public Enumeration getResources(String name) throws IOException {
if (SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION.equals(name)) {
- return Collections.enumeration(List.of(new File(
- "src/test/resources/org/springframework/boot/context/config/separate-class-loader-spring.factories")
- .toURI()
- .toURL()));
+ return super.getResources("separate-class-loader-spring.factories");
}
return super.getResources(name);
}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHintsTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHintsTests.java
index e4a822bd4db0..7db561f8198d 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHintsTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHintsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -28,6 +28,7 @@
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.boot.env.YamlPropertySourceLoader;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.test.io.support.MockSpringFactoriesLoader;
@@ -41,9 +42,11 @@
class ConfigDataLocationRuntimeHintsTests {
@Test
+ @WithResource(name = "application.properties", content = "")
+ @WithResource(name = "config/application.properties", content = "")
void registerWithDefaultSettings() {
RuntimeHints hints = new RuntimeHints();
- new TestConfigDataLocationRuntimeHints().registerHints(hints, null);
+ new TestConfigDataLocationRuntimeHints().registerHints(hints, Thread.currentThread().getContextClassLoader());
assertThat(hints.resources().resourcePatternHints()).singleElement()
.satisfies(includes("application*.properties", "application*.xml", "application*.yaml", "application*.yml",
"config/application*.properties", "config/application*.xml", "config/application*.yaml",
@@ -51,6 +54,8 @@ void registerWithDefaultSettings() {
}
@Test
+ @WithResource(name = "test.properties")
+ @WithResource(name = "config/test.properties")
void registerWithCustomName() {
RuntimeHints hints = new RuntimeHints();
new TestConfigDataLocationRuntimeHints() {
@@ -59,13 +64,15 @@ protected List getFileNames(ClassLoader classLoader) {
return List.of("test");
}
- }.registerHints(hints, null);
+ }.registerHints(hints, Thread.currentThread().getContextClassLoader());
assertThat(hints.resources().resourcePatternHints()).singleElement()
.satisfies(includes("test*.properties", "test*.xml", "test*.yaml", "test*.yml", "config/test*.properties",
"config/test*.xml", "config/test*.yaml", "config/test*.yml"));
}
@Test
+ @WithResource(name = "application.properties")
+ @WithResource(name = "config/application.properties")
void registerWithCustomLocation() {
RuntimeHints hints = new RuntimeHints();
new TestConfigDataLocationRuntimeHints() {
@@ -73,13 +80,15 @@ void registerWithCustomLocation() {
protected List getLocations(ClassLoader classLoader) {
return List.of("config/");
}
- }.registerHints(hints, null);
+ }.registerHints(hints, Thread.currentThread().getContextClassLoader());
assertThat(hints.resources().resourcePatternHints()).singleElement()
.satisfies(includes("config/application*.properties", "config/application*.xml", "config/application*.yaml",
"config/application*.yml"));
}
@Test
+ @WithResource(name = "application.conf")
+ @WithResource(name = "config/application.conf")
void registerWithCustomExtension() {
RuntimeHints hints = new RuntimeHints();
new ConfigDataLocationRuntimeHints() {
@@ -87,7 +96,7 @@ void registerWithCustomExtension() {
protected List getExtensions(ClassLoader classLoader) {
return List.of(".conf");
}
- }.registerHints(hints, null);
+ }.registerHints(hints, Thread.currentThread().getContextClassLoader());
assertThat(hints.resources().resourcePatternHints()).singleElement()
.satisfies(includes("application*.conf", "config/application*.conf"));
}
@@ -100,7 +109,7 @@ void registerWithUnknownLocationDoesNotAddHint() {
protected List getLocations(ClassLoader classLoader) {
return List.of(UUID.randomUUID().toString());
}
- }.registerHints(hints, null);
+ }.registerHints(hints, Thread.currentThread().getContextClassLoader());
assertThat(hints.resources().resourcePatternHints()).isEmpty();
}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLoaderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLoaderTests.java
index 908c4a29c0f5..ad06f8e77cbc 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLoaderTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLoaderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -22,6 +22,7 @@
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.env.YamlPropertySourceLoader;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
@@ -41,32 +42,36 @@ class StandardConfigDataLoaderTests {
private final ConfigDataLoaderContext loaderContext = mock(ConfigDataLoaderContext.class);
@Test
+ @WithResource(name = "application.yml", content = """
+ foo: bar
+ ---
+ hello: world
+ """)
void loadWhenLocationResultsInMultiplePropertySourcesAddsAllToConfigData() throws IOException {
- ClassPathResource resource = new ClassPathResource("configdata/yaml/application.yml");
+ ClassPathResource resource = new ClassPathResource("application.yml");
StandardConfigDataReference reference = new StandardConfigDataReference(
- ConfigDataLocation.of("classpath:configdata/yaml/application.yml"), null,
- "classpath:configdata/yaml/application", null, "yml", new YamlPropertySourceLoader());
+ ConfigDataLocation.of("classpath:application.yml"), null, "classpath:application", null, "yml",
+ new YamlPropertySourceLoader());
StandardConfigDataResource location = new StandardConfigDataResource(reference, resource);
ConfigData configData = this.loader.load(this.loaderContext, location);
assertThat(configData.getPropertySources()).hasSize(2);
PropertySource> source1 = configData.getPropertySources().get(0);
PropertySource> source2 = configData.getPropertySources().get(1);
- assertThat(source1.getName())
- .isEqualTo("Config resource 'class path resource [configdata/yaml/application.yml]' "
- + "via location 'classpath:configdata/yaml/application.yml' (document #0)");
+ assertThat(source1.getName()).isEqualTo("Config resource 'class path resource [application.yml]' "
+ + "via location 'classpath:application.yml' (document #0)");
assertThat(source1.getProperty("foo")).isEqualTo("bar");
- assertThat(source2.getName())
- .isEqualTo("Config resource 'class path resource [configdata/yaml/application.yml]' "
- + "via location 'classpath:configdata/yaml/application.yml' (document #1)");
+ assertThat(source2.getName()).isEqualTo("Config resource 'class path resource [application.yml]' "
+ + "via location 'classpath:application.yml' (document #1)");
assertThat(source2.getProperty("hello")).isEqualTo("world");
}
@Test
+ @WithResource(name = "empty.properties")
void loadWhenPropertySourceIsEmptyAddsNothingToConfigData() throws IOException {
- ClassPathResource resource = new ClassPathResource("config/0-empty/testproperties.properties");
+ ClassPathResource resource = new ClassPathResource("empty.properties");
StandardConfigDataReference reference = new StandardConfigDataReference(
- ConfigDataLocation.of("classpath:config/0-empty/testproperties.properties"), null,
- "config/0-empty/testproperties", null, "properties", new PropertiesPropertySourceLoader());
+ ConfigDataLocation.of("empty.properties"), null, "empty", null, "properties",
+ new PropertiesPropertySourceLoader());
StandardConfigDataResource location = new StandardConfigDataResource(reference, resource);
ConfigData configData = this.loader.load(this.loaderContext, location);
assertThat(configData.getPropertySources()).isEmpty();
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java
index eec8716dbaa0..183195037f68 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java
@@ -17,6 +17,7 @@
package org.springframework.boot.context.config;
import java.io.File;
+import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
@@ -26,6 +27,8 @@
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.logging.DeferredLogs;
+import org.springframework.boot.testsupport.classpath.resources.ResourcesRoot;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.DefaultResourceLoader;
@@ -72,23 +75,22 @@ void isResolvableAlwaysReturnsTrue() {
}
@Test
+ @WithResource(name = "configdata/application.properties")
void resolveWhenLocationIsDirectoryResolvesAllMatchingFilesInDirectory() {
- ConfigDataLocation location = ConfigDataLocation.of("classpath:/configdata/properties/");
+ ConfigDataLocation location = ConfigDataLocation.of("classpath:/configdata/");
List locations = this.resolver.resolve(this.context, location);
assertThat(locations).hasSize(1);
assertThat(locations).extracting(Object::toString)
- .containsExactly("class path resource [configdata/properties/application.properties]");
+ .containsExactly("class path resource [configdata/application.properties]");
}
@Test
void resolveWhenLocationIsFileResolvesFile() {
- ConfigDataLocation location = ConfigDataLocation
- .of("file:src/test/resources/configdata/properties/application.properties");
+ ConfigDataLocation location = ConfigDataLocation.of("file:configdata/application.properties");
List locations = this.resolver.resolve(this.context, location);
assertThat(locations).hasSize(1);
assertThat(locations).extracting(Object::toString)
- .containsExactly(
- filePath("src", "test", "resources", "configdata", "properties", "application.properties"));
+ .containsExactly(filePath("configdata", "application.properties"));
}
@Test
@@ -144,49 +146,55 @@ void resolveWhenLocationHasMultipleWildcardsThrowsException() {
}
@Test
- void resolveWhenLocationIsWildcardDirectoriesRestrictsToOneLevelDeep() {
- ConfigDataLocation location = ConfigDataLocation.of("file:src/test/resources/config/*/");
+ @WithResource(name = "config/0-empty/testproperties.properties")
+ @WithResource(name = "config/1-first/testproperties.properties", content = "first.property=apple")
+ @WithResource(name = "config/2-second/testproperties.properties", content = "second.property=ball")
+ @WithResource(name = "config/nested/3-third/testproperties.properties", content = "third.property=shouldnotbefound")
+ void resolveWhenLocationIsWildcardDirectoriesRestrictsToOneLevelDeep(@ResourcesRoot Path resourcesRoot) {
+ ConfigDataLocation location = ConfigDataLocation.of("file:" + resourcesRoot + "/config/*/");
this.environment.setProperty("spring.config.name", "testproperties");
this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
this.resourceLoader);
List locations = this.resolver.resolve(this.context, location);
assertThat(locations).hasSize(3);
assertThat(locations).extracting(Object::toString)
- .contains(filePath("src", "test", "resources", "config", "1-first", "testproperties.properties"))
- .contains(filePath("src", "test", "resources", "config", "2-second", "testproperties.properties"))
- .doesNotContain(filePath("src", "test", "resources", "config", "3-third", "testproperties.properties"));
+ .contains(filePath(resourcesRoot.resolve("config/1-first/testproperties.properties")))
+ .contains(filePath(resourcesRoot.resolve("config/2-second/testproperties.properties")))
+ .doesNotContain(filePath(resourcesRoot.resolve("config/nested/3-third/testproperties.properties")));
}
@Test
- void resolveWhenLocationIsWildcardDirectoriesSortsAlphabeticallyBasedOnAbsolutePath() {
- ConfigDataLocation location = ConfigDataLocation.of("file:src/test/resources/config/*/");
+ @WithResource(name = "config/0-empty/testproperties.properties")
+ @WithResource(name = "config/1-first/testproperties.properties", content = "first.property=apple")
+ @WithResource(name = "config/2-second/testproperties.properties", content = "second.property=ball")
+ @WithResource(name = "config/nested/3-third/testproperties.properties", content = "third.property=shouldnotbefound")
+ void resolveWhenLocationIsWildcardDirectoriesSortsAlphabeticallyBasedOnAbsolutePath(
+ @ResourcesRoot Path resourcesRoot) {
+ ConfigDataLocation location = ConfigDataLocation.of("file:" + resourcesRoot + "/config/*/");
this.environment.setProperty("spring.config.name", "testproperties");
this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
this.resourceLoader);
List locations = this.resolver.resolve(this.context, location);
assertThat(locations).extracting(Object::toString)
- .containsExactly(filePath("src", "test", "resources", "config", "0-empty", "testproperties.properties"),
- filePath("src", "test", "resources", "config", "1-first", "testproperties.properties"),
- filePath("src", "test", "resources", "config", "2-second", "testproperties.properties"));
+ .containsExactly(filePath(resourcesRoot.resolve("config/0-empty/testproperties.properties")),
+ filePath(resourcesRoot.resolve("config/1-first/testproperties.properties")),
+ filePath(resourcesRoot.resolve("config/2-second/testproperties.properties")));
}
@Test
- void resolveWhenLocationIsWildcardAndMatchingFilePresentShouldNotFail() {
- ConfigDataLocation location = ConfigDataLocation.of("optional:file:src/test/resources/a-file/*/");
- assertThatNoException().isThrownBy(() -> this.resolver.resolve(this.context, location));
- }
-
- @Test
- void resolveWhenLocationIsWildcardFilesLoadsAllFilesThatMatch() {
+ @WithResource(name = "config/0-empty/testproperties.properties")
+ @WithResource(name = "config/1-first/testproperties.properties", content = "first.property=apple")
+ @WithResource(name = "config/2-second/testproperties.properties", content = "second.property=ball")
+ @WithResource(name = "config/nested/3-third/testproperties.properties", content = "third.property=shouldnotbefound")
+ void resolveWhenLocationIsWildcardFilesLoadsAllFilesThatMatch(@ResourcesRoot Path resourcesRoot) {
ConfigDataLocation location = ConfigDataLocation
- .of("file:src/test/resources/config/*/testproperties.properties");
+ .of("file:" + resourcesRoot + "/config/*/testproperties.properties");
List locations = this.resolver.resolve(this.context, location);
assertThat(locations).hasSize(3);
assertThat(locations).extracting(Object::toString)
- .contains(filePath("src", "test", "resources", "config", "1-first", "testproperties.properties"))
- .contains(filePath("src", "test", "resources", "config", "2-second", "testproperties.properties"))
- .doesNotContain(
- filePath("src", "test", "resources", "config", "nested", "3-third", "testproperties.properties"));
+ .contains(filePath(resourcesRoot.resolve("config/1-first/testproperties.properties")))
+ .contains(filePath(resourcesRoot.resolve("config/2-second/testproperties.properties")))
+ .doesNotContain(filePath(resourcesRoot.resolve("config/nested/3-third/testproperties.properties")));
}
@Test
@@ -209,6 +217,8 @@ void resolveWhenLocationIsRelativeAndFileResolves() {
}
@Test
+ @WithResource(name = "config/specific.properties")
+ @WithResource(name = "config/nested/3-third/testproperties.properties")
void resolveWhenLocationIsRelativeAndDirectoryResolves() {
this.environment.setProperty("spring.config.name", "testproperties");
ConfigDataLocation location = ConfigDataLocation.of("nested/3-third/");
@@ -241,6 +251,7 @@ void resolveWhenLocationIsRelativeAndNoMatchingLoaderThrowsException() {
}
@Test
+ @WithResource(name = "application-props-no-extension", content = "withnoextension=test")
void resolveWhenLocationUsesOptionalExtensionSyntaxResolves() throws Exception {
ConfigDataLocation location = ConfigDataLocation.of("classpath:/application-props-no-extension[.properties]");
List locations = this.resolver.resolve(this.context, location);
@@ -249,19 +260,20 @@ void resolveWhenLocationUsesOptionalExtensionSyntaxResolves() throws Exception {
assertThat(resolved.getResource().getFilename()).endsWith("application-props-no-extension");
ConfigData loaded = new StandardConfigDataLoader().load(null, resolved);
PropertySource> propertySource = loaded.getPropertySources().get(0);
- assertThat(propertySource.getProperty("withnotext")).isEqualTo("test");
+ assertThat(propertySource.getProperty("withnoextension")).isEqualTo("test");
}
@Test
+ @WithResource(name = "application-dev.properties")
void resolveProfileSpecificReturnsProfileSpecificFiles() {
- ConfigDataLocation location = ConfigDataLocation.of("classpath:/configdata/properties/");
+ ConfigDataLocation location = ConfigDataLocation.of("classpath:/");
this.environment.setActiveProfiles("dev");
Profiles profiles = new Profiles(this.environment, this.environmentBinder, Collections.emptyList());
List locations = this.resolver.resolveProfileSpecific(this.context, location,
profiles);
assertThat(locations).hasSize(1);
assertThat(locations).extracting(Object::toString)
- .containsExactly("class path resource [configdata/properties/application-dev.properties]");
+ .containsExactly("class path resource [application-dev.properties]");
}
@Test
@@ -375,4 +387,8 @@ private String filePath(String... components) {
return "file [" + String.join(File.separator, components) + "]";
}
+ private String filePath(Path path) {
+ return "file [%s]".formatted(path);
+ }
+
}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java
index 1d8c729d22e6..44191581879a 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java
@@ -18,6 +18,10 @@
import java.io.File;
import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
@@ -62,6 +66,7 @@
import org.springframework.boot.logging.java.JavaLoggingSystem;
import org.springframework.boot.system.ApplicationPid;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
import org.springframework.context.ApplicationEvent;
@@ -160,8 +165,9 @@ void baseConfigLocation() {
}
@Test
+ @WithNonDefaultXmlResource
void overrideConfigLocation() {
- addPropertiesToEnvironment(this.context, "logging.config=classpath:logback-nondefault.xml");
+ addPropertiesToEnvironment(this.context, "logging.config=classpath:nondefault.xml");
this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader());
this.logger.info("Hello world");
assertThat(this.output).contains("Hello world").doesNotContain("???").startsWith("null ").endsWith("BOOTBOOT");
@@ -178,8 +184,9 @@ void throwableFromInitializeResultsInGracefulFailure(CapturedOutput output) {
}
@Test
+ @WithNonDefaultXmlResource
void trailingWhitespaceInLoggingConfigShouldBeTrimmed() {
- addPropertiesToEnvironment(this.context, "logging.config=classpath:logback-nondefault.xml ");
+ addPropertiesToEnvironment(this.context, "logging.config=classpath:nondefault.xml ");
this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader());
this.logger.info("Hello world");
assertThat(this.output).contains("Hello world").doesNotContain("???").startsWith("null ").endsWith("BOOTBOOT");
@@ -226,8 +233,9 @@ void overrideConfigBroken() {
}
@Test
+ @WithNonDefaultXmlResource
void addLogFileProperty() {
- addPropertiesToEnvironment(this.context, "logging.config=classpath:logback-nondefault.xml",
+ addPropertiesToEnvironment(this.context, "logging.config=classpath:nondefault.xml",
"logging.file.name=" + this.logFile);
this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
@@ -248,8 +256,9 @@ void addLogFilePropertyWithDefault() {
}
@Test
+ @WithNonDefaultXmlResource
void addLogPathProperty() {
- addPropertiesToEnvironment(this.context, "logging.config=classpath:logback-nondefault.xml",
+ addPropertiesToEnvironment(this.context, "logging.config=classpath:nondefault.xml",
"logging.file.path=" + this.tempDir);
this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
@@ -779,4 +788,22 @@ public int getPhase() {
}
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.RUNTIME)
+ @WithResource(name = "nondefault.xml", content = """
+
+
+
+ %property{LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT
+
+
+
+
+
+
+ """)
+ private @interface WithNonDefaultXmlResource {
+
+ }
+
}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java
index 3c80f26dfa48..a223cfa1a66e 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java
@@ -70,6 +70,7 @@
import org.springframework.boot.convert.PeriodStyle;
import org.springframework.boot.convert.PeriodUnit;
import org.springframework.boot.env.RandomValuePropertySource;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -262,6 +263,21 @@ void loadWhenBindingWithoutAnnotationValueShouldBind() {
}
@Test
+ @WithResource(name = "testProperties.xml",
+ content = """
+
+
+
+
+
+
+
+
+ """)
void loadWhenBindingWithDefaultsInXmlShouldBind() {
removeSystemProperties();
load(new Class>[] { DefaultsInXmlConfiguration.class });
@@ -654,6 +670,7 @@ void customProtocolResolverIsInvoked() {
}
@Test
+ @WithResource(name = "application.properties")
void customProtocolResolver() {
this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
@@ -1377,7 +1394,7 @@ static class WithoutAnnotationValueConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
- @ImportResource("org/springframework/boot/context/properties/testProperties.xml")
+ @ImportResource("testProperties.xml")
static class DefaultsInXmlConfiguration {
}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToFileConverterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToFileConverterTests.java
index a3cb2b37af07..015e6ab1cfad 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToFileConverterTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToFileConverterTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -23,6 +23,7 @@
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.provider.Arguments;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.ClassPathResource;
@@ -52,9 +53,10 @@ void convertWhenFilePrefixedReturnsFile(ConversionService conversionService) {
}
@ConversionServiceTest
+ @WithResource(name = "com/example/test-file.txt", content = "test content")
void convertWhenClasspathPrefixedReturnsFile(ConversionService conversionService) throws IOException {
- String resource = new ClassPathResource("test-banner.txt", this.getClass().getClassLoader()).getURL().getFile();
- assertThat(convert(conversionService, "classpath:test-banner.txt").getAbsoluteFile())
+ String resource = new ClassPathResource("com/example/test-file.txt").getURL().getFile();
+ assertThat(convert(conversionService, "classpath:com/example/test-file.txt").getAbsoluteFile())
.isEqualTo(new File(resource).getAbsoluteFile());
}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java
index e67fc5240628..ba440e31827e 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -25,6 +25,7 @@
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.springframework.boot.diagnostics.analyzer.nounique.TestBean;
import org.springframework.boot.diagnostics.analyzer.nounique.TestBeanConsumer;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@@ -39,6 +40,17 @@
* @author Andy Wilkinson
* @author Scott Frederick
*/
+@WithResource(name = "producer.xml",
+ content = """
+
+
+
+
+
+
+ """)
class NoUniqueBeanDefinitionFailureAnalyzerTests {
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@@ -79,6 +91,17 @@ void failureAnalysisForObjectProviderMethodConsumer() {
}
@Test
+ @WithResource(name = "consumer.xml",
+ content = """
+
+
+
+
+
+
+ """)
void failureAnalysisForXmlConsumer() {
FailureAnalysis failureAnalysis = analyzeFailure(createFailure(XmlConsumer.class));
assertThat(failureAnalysis.getDescription()).startsWith("Parameter 0 of constructor in "
@@ -147,7 +170,7 @@ private void assertFoundBeans(FailureAnalysis analysis) {
@Configuration(proxyBeanMethods = false)
@ComponentScan(basePackageClasses = TestBean.class)
- @ImportResource("/org/springframework/boot/diagnostics/analyzer/nounique/producer.xml")
+ @ImportResource("classpath:producer.xml")
static class DuplicateBeansProducer {
@Bean
@@ -216,7 +239,7 @@ String consumer(ObjectProvider testBeanProvider) {
}
@Configuration(proxyBeanMethods = false)
- @ImportResource("/org/springframework/boot/diagnostics/analyzer/nounique/consumer.xml")
+ @ImportResource("classpath:consumer.xml")
static class XmlConsumer {
}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java
index 6fdb3e743bb4..e5f3e7d399e1 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -26,6 +26,7 @@
import org.springframework.boot.env.OriginTrackedPropertiesLoader.Document;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.TextResourceOrigin;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
@@ -92,9 +93,10 @@ void getUnicodeProperty() {
}
@Test
+ @WithResource(name = "malformed-unicode.properties", content = "test-malformed-unicode=properties\\u(026test")
void getMalformedUnicodeProperty() {
// gh-12716
- ClassPathResource resource = new ClassPathResource("test-properties-malformed-unicode.properties", getClass());
+ ClassPathResource resource = new ClassPathResource("malformed-unicode.properties");
assertThatIllegalStateException().isThrownBy(() -> new OriginTrackedPropertiesLoader(resource).load())
.withMessageContaining("Malformed \\uxxxx encoding");
}
@@ -326,8 +328,43 @@ void getPropertyWithEscapedTrailingSpace() {
}
@Test
+ @WithResource(name = "existing-non-multi-document.properties", content = """
+ #---
+ # Test
+ #---
+
+ spring=boot
+
+ #---
+ # Test
+
+ boot=bar
+
+
+ # Test
+ #---
+
+ bar=ok
+
+ !---
+ ! Test
+ !---
+
+ ok=well
+
+ !---
+ ! Test
+
+ well=hello
+
+ ! Test
+ !---
+
+ hello=world
+
+ """)
void existingCommentsAreNotTreatedAsMultiDoc() throws Exception {
- this.resource = new ClassPathResource("existing-non-multi-document.properties", getClass());
+ this.resource = new ClassPathResource("existing-non-multi-document.properties");
this.documents = new OriginTrackedPropertiesLoader(this.resource).load();
assertThat(this.documents).hasSize(1);
}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedYamlLoaderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedYamlLoaderTests.java
index 58720b002351..86cc0e9de17d 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedYamlLoaderTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedYamlLoaderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 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.
@@ -16,6 +16,10 @@
package org.springframework.boot.env;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
@@ -26,6 +30,7 @@
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.TextResourceOrigin;
+import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@@ -47,11 +52,12 @@ class OriginTrackedYamlLoaderTests {
@BeforeEach
void setUp() {
- Resource resource = new ClassPathResource("test-yaml.yml", getClass());
+ Resource resource = new ClassPathResource("test-yaml.yml");
this.loader = new OriginTrackedYamlLoader(resource);
}
@Test
+ @WithTestYamlResource
void processSimpleKey() {
OriginTrackedValue value = getValue("name");
assertThat(value).hasToString("Martin D'vloper");
@@ -59,6 +65,7 @@ void processSimpleKey() {
}
@Test
+ @WithTestYamlResource
void processMap() {
OriginTrackedValue perl = getValue("languages.perl");
OriginTrackedValue python = getValue("languages.python");
@@ -72,6 +79,7 @@ void processMap() {
}
@Test
+ @WithTestYamlResource
void processCollection() {
OriginTrackedValue apple = getValue("foods[0]");
OriginTrackedValue orange = getValue("foods[1]");
@@ -88,6 +96,7 @@ void processCollection() {
}
@Test
+ @WithTestYamlResource
void processMultiline() {
OriginTrackedValue education = getValue("education");
assertThat(education).hasToString("4 GCSEs\n3 A-Levels\nBSc in the Internet of Things\n");
@@ -95,6 +104,7 @@ void processMultiline() {
}
@Test
+ @WithTestYamlResource
void processListOfMaps() {
OriginTrackedValue name = getValue("example.foo[0].name");
OriginTrackedValue url = getValue("example.foo[0].url");
@@ -111,6 +121,7 @@ void processListOfMaps() {
}
@Test
+ @WithTestYamlResource
void processEmptyAndNullValues() {
OriginTrackedValue empty = getValue("empty");
OriginTrackedValue nullValue = getValue("null-value");
@@ -124,6 +135,7 @@ void processEmptyAndNullValues() {
}
@Test
+ @WithTestYamlResource
void emptyMapsAreDropped() {
Object emptyMap = getValue("emptymap");
assertThat(emptyMap).isNull();
@@ -138,8 +150,15 @@ void unsupportedType() {
}
@Test
+ @WithResource(name = "test-empty-yaml.yml", content = """
+ ---
+ ---
+
+ ---
+ ---
+ """)
void emptyDocuments() {
- this.loader = new OriginTrackedYamlLoader(new ClassPathResource("test-empty-yaml.yml", getClass()));
+ this.loader = new OriginTrackedYamlLoader(new ClassPathResource("test-empty-yaml.yml"));
List