Minimize test resources and move remainder to appropriate packages

Closes gh-44397
This commit is contained in:
Andy Wilkinson 2025-02-25 21:10:19 +00:00
parent 8577718b22
commit 3de189a1df
303 changed files with 2857 additions and 1253 deletions

View File

@ -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 sampleconfig.MyComponentInPackageWithoutDot;
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 @@ class BeanDefinitionLoaderTests {
}
@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 @@ class BeanDefinitionLoaderTests {
}
@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 @@ class BeanDefinitionLoaderTests {
}
@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 @@ class BeanDefinitionLoaderTests {
}
@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 @@ class BeanDefinitionLoaderTests {
}
@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");

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 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.
@ -61,12 +61,14 @@ class SimpleMainTests {
}
@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);

View File

@ -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.mockito.ArgumentCaptor;
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 @@ class SpringApplicationBannerPrinterTests {
}
@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);

View File

@ -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.
@ -74,6 +74,7 @@ import org.springframework.boot.context.event.ApplicationStartingEvent;
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 @@ class SpringApplicationTests {
}
@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");
}
@ -289,6 +295,7 @@ class SpringApplicationTests {
}
@Test
@WithResource(name = "bindtoapplication.properties", content = "spring.main.banner-mode=off")
void triggersConfigFileApplicationListenerBeforeBinding() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@ -540,6 +547,7 @@ class SpringApplicationTests {
}
@Test
@WithResource(name = "application.properties", content = "foo=bucket")
void propertiesFileEnhancesEnvironment() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@ -572,6 +580,8 @@ class SpringApplicationTests {
}
@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);
@ -584,6 +594,7 @@ class SpringApplicationTests {
}
@Test
@WithResource(name = "application.properties", content = "foo=bucket")
void emptyCommandLinePropertySourceNotAdded() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@ -814,11 +825,13 @@ class SpringApplicationTests {
}
@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
@ -1139,6 +1152,8 @@ class SpringApplicationTests {
}
@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");
@ -1195,6 +1210,7 @@ class SpringApplicationTests {
}
@Test
@WithResource(name = "custom-config/application.yml", content = "hello: world")
void relaxedBindingShouldWorkBeforeEnvironmentIsPrepared() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@ -1329,6 +1345,8 @@ class SpringApplicationTests {
}
@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);

View File

@ -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 = """
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="myXmlComponent" class="org.springframework.boot.sampleconfig.MyComponent"/>
</beans>
""")
@interface WithSampleBeansXmlResource {
}

View File

@ -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.
@ -29,6 +29,7 @@ import org.springframework.boot.ApplicationContextFactory;
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 @@ class SpringApplicationBuilderTests {
}
@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 @@ class SpringApplicationBuilderTests {
}
@Test
@WithResource(name = "application-node.properties", content = "bar=spam")
void parentFirstCreationWithProfileAndDefaultArgs() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class).profiles("node")
.properties("transport=redis")

View File

@ -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 java.lang.annotation.Target;
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 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
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");

View File

@ -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.WebApplicationType;
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 @@ class AnsiOutputApplicationListenerTests {
}
@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);

View File

@ -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.BootstrapRegistry;
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 @@ class ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests {
}
@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");

View File

@ -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.WebApplicationType;
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 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @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 @@ class ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegra
@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");
}

View File

@ -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.mockito.junit.jupiter.MockitoExtension;
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 @@ class ConfigDataEnvironmentPostProcessorTests {
}
@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();

View File

@ -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.Map;
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.ConfigDataEnvironmentContributor.
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 @@ class ConfigDataEnvironmentTests {
}
@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 @@ class ConfigDataEnvironmentTests {
}
@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 @@ class ConfigDataEnvironmentTests {
}
@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 @@ class ConfigDataEnvironmentTests {
}
@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 @@ class ConfigDataEnvironmentTests {
}
@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 @@ class ConfigDataEnvironmentTests {
}
@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 @@ class ConfigDataEnvironmentTests {
}
@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 @@ class ConfigDataEnvironmentTests {
}
@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 @@ class ConfigDataEnvironmentTests {
}
@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 @@ class ConfigDataEnvironmentTests {
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 @@ class ConfigDataEnvironmentTests {
@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<URL> 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);
}

View File

@ -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.aot.hint.RuntimeHints;
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 @@ import static org.assertj.core.api.Assertions.assertThat;
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 @@ class ConfigDataLocationRuntimeHintsTests {
}
@Test
@WithResource(name = "test.properties")
@WithResource(name = "config/test.properties")
void registerWithCustomName() {
RuntimeHints hints = new RuntimeHints();
new TestConfigDataLocationRuntimeHints() {
@ -59,13 +64,15 @@ class ConfigDataLocationRuntimeHintsTests {
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 @@ class ConfigDataLocationRuntimeHintsTests {
protected List<String> 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 @@ class ConfigDataLocationRuntimeHintsTests {
protected List<String> 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 @@ class ConfigDataLocationRuntimeHintsTests {
protected List<String> getLocations(ClassLoader classLoader) {
return List.of(UUID.randomUUID().toString());
}
}.registerHints(hints, null);
}.registerHints(hints, Thread.currentThread().getContextClassLoader());
assertThat(hints.resources().resourcePatternHints()).isEmpty();
}

View File

@ -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.junit.jupiter.api.Test;
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();

View File

@ -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.
@ -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.junit.jupiter.api.Test;
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;
@ -71,23 +74,22 @@ class StandardConfigDataLocationResolverTests {
}
@Test
@WithResource(name = "configdata/application.properties")
void resolveWhenLocationIsDirectoryResolvesAllMatchingFilesInDirectory() {
ConfigDataLocation location = ConfigDataLocation.of("classpath:/configdata/properties/");
ConfigDataLocation location = ConfigDataLocation.of("classpath:/configdata/");
List<StandardConfigDataResource> 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<StandardConfigDataResource> 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
@ -143,49 +145,55 @@ class StandardConfigDataLocationResolverTests {
}
@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<StandardConfigDataResource> 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<StandardConfigDataResource> 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<StandardConfigDataResource> 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
@ -208,6 +216,8 @@ class StandardConfigDataLocationResolverTests {
}
@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/");
@ -240,6 +250,7 @@ class StandardConfigDataLocationResolverTests {
}
@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<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);
@ -248,19 +259,20 @@ class StandardConfigDataLocationResolverTests {
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:/");
Profiles profiles = mock(Profiles.class);
given(profiles.iterator()).willReturn(Collections.singletonList("dev").iterator());
List<StandardConfigDataResource> 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
@ -297,4 +309,8 @@ class StandardConfigDataLocationResolverTests {
return "file [" + String.join(File.separator, components) + "]";
}
private String filePath(Path path) {
return "file [%s]".formatted(path);
}
}

View File

@ -18,6 +18,10 @@ package org.springframework.boot.context.logging;
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.LoggingSystemProperty;
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 @@ class LoggingApplicationListenerTests {
}
@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 @@ class LoggingApplicationListenerTests {
}
@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 @@ class LoggingApplicationListenerTests {
}
@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 @@ class LoggingApplicationListenerTests {
}
@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 @@ class LoggingApplicationListenerTests {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "nondefault.xml", content = """
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%property{LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
""")
private @interface WithNonDefaultXmlResource {
}
}

View File

@ -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.
@ -69,6 +69,7 @@ import org.springframework.boot.convert.PeriodFormat;
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;
@ -260,6 +261,21 @@ class ConfigurationPropertiesTests {
}
@Test
@WithResource(name = "testProperties.xml",
content = """
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean
id="org.springframework.boot.context.properties.ConfigurationPropertiesTests$BasicProperties"
class="org.springframework.boot.context.properties.ConfigurationPropertiesTests$BasicProperties">
<property name="name" value="bar"/>
</bean>
</beans>
""")
void loadWhenBindingWithDefaultsInXmlShouldBind() {
removeSystemProperties();
load(new Class<?>[] { DefaultsInXmlConfiguration.class });
@ -633,6 +649,7 @@ class ConfigurationPropertiesTests {
}
@Test
@WithResource(name = "application.properties")
void customProtocolResolver() {
this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
@ -1356,7 +1373,7 @@ class ConfigurationPropertiesTests {
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ImportResource("org/springframework/boot/context/properties/testProperties.xml")
@ImportResource("testProperties.xml")
static class DefaultsInXmlConfiguration {
}

View File

@ -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 java.util.stream.Stream;
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 @@ class StringToFileConverterTests {
}
@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());
}

View File

@ -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.
@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
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;
@ -38,6 +39,17 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Andy Wilkinson
* @author Scott Frederick
*/
@WithResource(name = "producer.xml",
content = """
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.boot.diagnostics.analyzer.nounique.TestBean" name="xmlTestBean"/>
</beans>
""")
class NoUniqueBeanDefinitionFailureAnalyzerTests {
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@ -78,6 +90,17 @@ class NoUniqueBeanDefinitionFailureAnalyzerTests {
}
@Test
@WithResource(name = "consumer.xml",
content = """
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.boot.diagnostics.analyzer.nounique.TestBeanConsumer"/>
</beans>
""")
void failureAnalysisForXmlConsumer() {
FailureAnalysis failureAnalysis = analyzeFailure(createFailure(XmlConsumer.class));
assertThat(failureAnalysis.getDescription()).startsWith("Parameter 0 of constructor in "
@ -131,7 +154,7 @@ class NoUniqueBeanDefinitionFailureAnalyzerTests {
@Configuration(proxyBeanMethods = false)
@ComponentScan(basePackageClasses = TestBean.class)
@ImportResource("/org/springframework/boot/diagnostics/analyzer/nounique/producer.xml")
@ImportResource("classpath:producer.xml")
static class DuplicateBeansProducer {
@Bean
@ -200,7 +223,7 @@ class NoUniqueBeanDefinitionFailureAnalyzerTests {
}
@Configuration(proxyBeanMethods = false)
@ImportResource("/org/springframework/boot/diagnostics/analyzer/nounique/consumer.xml")
@ImportResource("classpath:consumer.xml")
static class XmlConsumer {
}

View File

@ -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.junit.jupiter.api.Test;
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 @@ class OriginTrackedPropertiesLoaderTests {
}
@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 @@ class OriginTrackedPropertiesLoaderTests {
}
@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);
}

View File

@ -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.
@ -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.Collections;
import java.util.List;
@ -27,6 +31,7 @@ import org.yaml.snakeyaml.composer.ComposerException;
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;
@ -48,11 +53,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");
@ -60,6 +66,7 @@ class OriginTrackedYamlLoaderTests {
}
@Test
@WithTestYamlResource
void processMap() {
OriginTrackedValue perl = getValue("languages.perl");
OriginTrackedValue python = getValue("languages.python");
@ -73,6 +80,7 @@ class OriginTrackedYamlLoaderTests {
}
@Test
@WithTestYamlResource
void processCollection() {
OriginTrackedValue apple = getValue("foods[0]");
OriginTrackedValue orange = getValue("foods[1]");
@ -89,6 +97,7 @@ class OriginTrackedYamlLoaderTests {
}
@Test
@WithTestYamlResource
void processMultiline() {
OriginTrackedValue education = getValue("education");
assertThat(education).hasToString("4 GCSEs\n3 A-Levels\nBSc in the Internet of Things\n");
@ -96,6 +105,7 @@ class OriginTrackedYamlLoaderTests {
}
@Test
@WithTestYamlResource
void processListOfMaps() {
OriginTrackedValue name = getValue("example.foo[0].name");
OriginTrackedValue url = getValue("example.foo[0].url");
@ -112,6 +122,7 @@ class OriginTrackedYamlLoaderTests {
}
@Test
@WithTestYamlResource
void processEmptyAndNullValues() {
OriginTrackedValue empty = getValue("empty");
OriginTrackedValue nullValue = getValue("null-value");
@ -122,6 +133,7 @@ class OriginTrackedYamlLoaderTests {
}
@Test
@WithTestYamlResource
void processEmptyListAndMap() {
OriginTrackedValue emptymap = getValue("emptymap");
OriginTrackedValue emptylist = getValue("emptylist");
@ -138,8 +150,15 @@ class OriginTrackedYamlLoaderTests {
}
@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<Map<String, Object>> loaded = this.loader.load();
assertThat(loaded).isEmpty();
}
@ -165,8 +184,17 @@ class OriginTrackedYamlLoaderTests {
}
@Test
@WithResource(name = "recursive.yml", content = """
&def1
*def1: a
test:
a:
spring: 'a'
b:
boot: 'b'
""")
void loadWhenRecursiveLoadsYaml() {
Resource resource = new ClassPathResource("recursive.yml", getClass());
Resource resource = new ClassPathResource("recursive.yml");
this.loader = new OriginTrackedYamlLoader(resource);
Map<String, Object> loaded = this.loader.load().get(0);
assertThat(loaded.get("test.a.spring")).hasToString("a");
@ -174,8 +202,16 @@ class OriginTrackedYamlLoaderTests {
}
@Test
@WithResource(name = "anchors.yml", content = """
some:
path: &anchor
config:
key: value
anotherpath:
<<: *anchor
""")
void loadWhenUsingAnchors() {
Resource resource = new ClassPathResource("anchors.yml", getClass());
Resource resource = new ClassPathResource("anchors.yml");
this.loader = new OriginTrackedYamlLoader(resource);
Map<String, Object> loaded = this.loader.load().get(0);
assertThat(loaded.get("some.path.config.key")).hasToString("value");
@ -205,4 +241,49 @@ class OriginTrackedYamlLoaderTests {
return ((TextResourceOrigin) value.getOrigin()).getLocation().toString();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@WithResource(name = "test-yaml.yml", content = """
# https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
name: Martin D'vloper
job: Developer
skill: Elite
employed: True
foods:
- Apple
- Orange
- Strawberry
- Mango
languages:
perl: Elite
python: Elite
pascal: Lame
education: |
4 GCSEs
3 A-Levels
BSc in the Internet of Things
example:
foo:
- name: springboot
url: https://springboot.example.com/
bar:
- bar1: baz
- bar2: bling
empty: ""
null-value: null
emptylist: []
emptymap: {}
---
spring:
profiles: development
name: Test Name
---
""")
private @interface WithTestYamlResource {
}
}

View File

@ -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,6 +20,7 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
@ -41,17 +42,28 @@ class PropertiesPropertySourceLoaderTests {
}
@Test
@WithResource(name = "test.properties", content = "test=properties")
void loadProperties() throws Exception {
List<PropertySource<?>> loaded = this.loader.load("test.properties",
new ClassPathResource("test-properties.properties", getClass()));
List<PropertySource<?>> loaded = this.loader.load("test.properties", new ClassPathResource("test.properties"));
PropertySource<?> source = loaded.get(0);
assertThat(source.getProperty("test")).isEqualTo("properties");
}
@Test
@WithResource(name = "test.properties", content = """
#---
#test
blah=hello world
bar=baz
hello=world
#---
foo=bar
bling=biz
#comment1
#comment2
""")
void loadMultiDocumentPropertiesWithSeparatorAtTheBeginningOfFile() throws Exception {
List<PropertySource<?>> loaded = this.loader.load("test.properties",
new ClassPathResource("multi-document-properties-2.properties", getClass()));
List<PropertySource<?>> loaded = this.loader.load("test.properties", new ClassPathResource("test.properties"));
assertThat(loaded).hasSize(2);
PropertySource<?> source1 = loaded.get(0);
PropertySource<?> source2 = loaded.get(1);
@ -60,9 +72,20 @@ class PropertiesPropertySourceLoaderTests {
}
@Test
@WithResource(name = "test.properties", content = """
#test
blah=hello world
bar=baz
hello=world
#---
foo=bar
bling=biz
#comment1
#comment2
#---
""")
void loadMultiDocumentProperties() throws Exception {
List<PropertySource<?>> loaded = this.loader.load("test.properties",
new ClassPathResource("multi-document-properties.properties", getClass()));
List<PropertySource<?>> loaded = this.loader.load("test.properties", new ClassPathResource("test.properties"));
assertThat(loaded).hasSize(2);
PropertySource<?> source1 = loaded.get(0);
PropertySource<?> source2 = loaded.get(1);
@ -71,9 +94,22 @@ class PropertiesPropertySourceLoaderTests {
}
@Test
@WithResource(name = "test.properties", content = """
#---
#test
blah=hello world
bar=baz
hello=world
#---
#---
foo=bar
bling=biz
#comment1
#comment2
""")
void loadMultiDocumentPropertiesWithEmptyDocument() throws Exception {
List<PropertySource<?>> loaded = this.loader.load("test.properties",
new ClassPathResource("multi-document-properties-empty.properties", getClass()));
List<PropertySource<?>> loaded = this.loader.load("test.properties", new ClassPathResource("test.properties"));
assertThat(loaded).hasSize(2);
PropertySource<?> source1 = loaded.get(0);
PropertySource<?> source2 = loaded.get(1);
@ -82,9 +118,15 @@ class PropertiesPropertySourceLoaderTests {
}
@Test
@WithResource(name = "test.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="test">xml</entry>
</properties>
""")
void loadXml() throws Exception {
List<PropertySource<?>> loaded = this.loader.load("test.xml",
new ClassPathResource("test-xml.xml", getClass()));
List<PropertySource<?>> loaded = this.loader.load("test.xml", new ClassPathResource("test.xml"));
PropertySource<?> source = loaded.get(0);
assertThat(source.getProperty("test")).isEqualTo("xml");
}

View File

@ -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.
@ -21,6 +21,7 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ByteArrayResource;
@ -86,8 +87,14 @@ class YamlPropertySourceLoaderTests {
}
@Test
@WithResource(name = "test-yaml.yml", content = """
a: b
---
c: d
e: f
""")
void loadOriginAware() throws Exception {
Resource resource = new ClassPathResource("test-yaml.yml", getClass());
Resource resource = new ClassPathResource("test-yaml.yml");
List<PropertySource<?>> loaded = this.loader.load("resource", resource);
for (PropertySource<?> source : loaded) {
EnumerablePropertySource<?> enumerableSource = (EnumerablePropertySource<?>) source;

View File

@ -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.
@ -70,6 +70,7 @@ class DataSourceScriptDatabaseInitializerTests
}
@Test
@WithDataSqlResource
void whenCustomizeIsOverriddenThenDatabasePopulatorIsConfiguredAccordingly() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setContinueOnError(true);

View File

@ -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,15 +16,14 @@
package org.springframework.boot.json;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.springframework.util.StreamUtils;
import org.springframework.boot.testsupport.classpath.resources.ResourceContent;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -192,26 +191,22 @@ abstract class AbstractJsonParserTests {
}
@Test // gh-31868
void listWithRepeatedOpenArray() throws IOException {
String input = StreamUtils.copyToString(
AbstractJsonParserTests.class.getResourceAsStream("repeated-open-array.txt"), StandardCharsets.UTF_8);
@WithPackageResources("repeated-open-array.txt")
void listWithRepeatedOpenArray(@ResourceContent("repeated-open-array.txt") String input) {
assertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseList(input))
.havingCause()
.withMessageContaining("too deeply nested");
}
@Test // gh-31869
void largeMalformed() throws IOException {
String input = StreamUtils.copyToString(
AbstractJsonParserTests.class.getResourceAsStream("large-malformed-json.txt"), StandardCharsets.UTF_8);
@WithPackageResources("large-malformed-json.txt")
void largeMalformed(@ResourceContent("large-malformed-json.txt") String input) {
assertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseList(input));
}
@Test // gh-32029
void deeplyNestedMap() throws IOException {
String input = StreamUtils.copyToString(
AbstractJsonParserTests.class.getResourceAsStream("deeply-nested-map-json.txt"),
StandardCharsets.UTF_8);
@WithPackageResources("deeply-nested-map-json.txt")
void deeplyNestedMap(@ResourceContent("deeply-nested-map-json.txt") String input) {
assertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseList(input));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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,8 +16,6 @@
package org.springframework.boot.json;
import java.io.IOException;
/**
* Tests for {@link GsonJsonParser}.
*
@ -31,7 +29,7 @@ class GsonJsonParserTests extends AbstractJsonParserTests {
}
@Override
void listWithRepeatedOpenArray() throws IOException {
void listWithRepeatedOpenArray(String input) {
// Gson does not protect against deeply nested JSON
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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.
@ -52,7 +52,7 @@ class JacksonJsonParserTests extends AbstractJsonParserTests {
@Override
@Disabled("Jackson's array handling is no longer stack bound so protection has been removed.")
// https://github.com/FasterXML/jackson-databind/commit/8238ab41d0350fb915797c89d46777b4496b74fd
void listWithRepeatedOpenArray() throws IOException {
void listWithRepeatedOpenArray(String input) {
}

View File

@ -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.
@ -34,6 +34,7 @@ import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggerConfiguration;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.logging.LoggingSystemProperty;
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.util.ClassUtils;
@ -123,6 +124,10 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithResource(name = "logging-nondefault.properties", content = """
handlers = java.util.logging.ConsoleHandler
.level = INFO
""")
void testNonDefaultConfigLocation(CapturedOutput output) {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, "classpath:logging-nondefault.properties", null);

View File

@ -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.
@ -19,6 +19,10 @@ package org.springframework.boot.logging.log4j2;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.ProtocolException;
import java.util.EnumSet;
import java.util.LinkedHashMap;
@ -59,6 +63,7 @@ import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.logging.LoggingSystemProperties;
import org.springframework.boot.logging.LoggingSystemProperty;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.testsupport.logging.ConfigureClasspathToPreferLog4j2;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
@ -158,16 +163,16 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithNonDefaultXmlResource
void testNonDefaultConfigLocation(CapturedOutput output) {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(this.initializationContext, "classpath:log4j2-nondefault.xml",
this.loggingSystem.initialize(this.initializationContext, "classpath:nondefault.xml",
getLogFile(tmpDir() + "/tmp.log", null));
this.logger.info("Hello world");
Configuration configuration = this.loggingSystem.getConfiguration();
assertThat(output).contains("Hello world").contains(tmpDir() + "/tmp.log");
assertThat(new File(tmpDir() + "/tmp.log")).doesNotExist();
assertThat(configuration.getConfigurationSource().getFile().getAbsolutePath())
.contains("log4j2-nondefault.xml");
assertThat(configuration.getConfigurationSource().getFile().getAbsolutePath()).contains("nondefault.xml");
assertThat(configuration.getWatchManager().getIntervalSeconds()).isEqualTo(30);
}
@ -461,15 +466,18 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithNonDefaultXmlResource
@WithOverrideXmlResource
void compositeConfigurationWithCustomBaseConfiguration() {
this.environment.setProperty("logging.log4j2.config.override", "src/test/resources/log4j2-override.xml");
this.loggingSystem.initialize(this.initializationContext, "src/test/resources/log4j2-nondefault.xml", null);
this.environment.setProperty("logging.log4j2.config.override", "classpath:override.xml");
this.loggingSystem.initialize(this.initializationContext, "classpath:nondefault.xml", null);
assertThat(this.loggingSystem.getConfiguration()).isInstanceOf(CompositeConfiguration.class);
}
@Test
@WithOverrideXmlResource
void compositeConfigurationWithStandardConfigLocationConfiguration() {
this.environment.setProperty("logging.log4j2.config.override", "src/test/resources/log4j2-override.xml");
this.environment.setProperty("logging.log4j2.config.override", "classpath:override.xml");
this.loggingSystem.initialize(this.initializationContext, null, null);
assertThat(this.loggingSystem.getConfiguration()).isInstanceOf(CompositeConfiguration.class);
}
@ -678,4 +686,45 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "nondefault.xml",
content = """
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="PID">????</Property>
<Property name="LOG_PATTERN">${sys:LOG_FILE} %d{yyyy-MM-dd HH:mm:ss.SSS}] service%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
""")
private @interface WithNonDefaultXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "override.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}"/>
</Console>
</Appenders>
</Configuration>
""")
private @interface WithOverrideXmlResource {
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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.logging.log4j2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
@ -32,12 +36,12 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.testsupport.logging.ConfigureClasspathToPreferLog4j2;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -93,6 +97,7 @@ class SpringProfileArbiterTests {
}
@Test
@WithProductionProfileXmlResource
void profileActive() {
this.environment.setActiveProfiles("production");
initialize("production-profile.xml");
@ -101,6 +106,7 @@ class SpringProfileArbiterTests {
}
@Test
@WithMultiProfileNamesXmlResource
void multipleNamesFirstProfileActive() {
this.environment.setActiveProfiles("production");
initialize("multi-profile-names.xml");
@ -109,6 +115,7 @@ class SpringProfileArbiterTests {
}
@Test
@WithMultiProfileNamesXmlResource
void multipleNamesSecondProfileActive() {
this.environment.setActiveProfiles("test");
initialize("multi-profile-names.xml");
@ -117,6 +124,7 @@ class SpringProfileArbiterTests {
}
@Test
@WithProductionProfileXmlResource
void profileNotActive() {
initialize("production-profile.xml");
this.logger.trace("Hello");
@ -124,6 +132,7 @@ class SpringProfileArbiterTests {
}
@Test
@WithProfileExpressionXmlResource
void profileExpressionMatchFirst() {
this.environment.setActiveProfiles("production");
initialize("profile-expression.xml");
@ -132,6 +141,7 @@ class SpringProfileArbiterTests {
}
@Test
@WithProfileExpressionXmlResource
void profileExpressionMatchSecond() {
this.environment.setActiveProfiles("test");
initialize("profile-expression.xml");
@ -140,6 +150,7 @@ class SpringProfileArbiterTests {
}
@Test
@WithProfileExpressionXmlResource
void profileExpressionNoMatch() {
this.environment.setActiveProfiles("development");
initialize("profile-expression.xml");
@ -148,13 +159,56 @@ class SpringProfileArbiterTests {
}
private void initialize(String config) {
this.environment.setProperty("logging.log4j2.config.override", getPackageResource(config));
this.environment.setProperty("logging.log4j2.config.override", "classpath:" + config);
this.loggingSystem.initialize(this.initializationContext, null, null);
}
private String getPackageResource(String fileName) {
String path = ClassUtils.getPackageName(getClass());
return "src/test/resources/" + path.replace('.', '/') + "/" + fileName;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "multi-profile-names.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<SpringProfile name="production, test">
<Loggers>
<Logger name="org.springframework.boot.logging.log4j2" level="TRACE" />
</Loggers>
</SpringProfile>
</Configuration>
""")
private @interface WithMultiProfileNamesXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "profile-expression.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<SpringProfile name="production | test">
<Loggers>
<Logger name="org.springframework.boot.logging.log4j2" level="TRACE" />
</Loggers>
</SpringProfile>
</Configuration>
""")
private @interface WithProfileExpressionXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "production-profile.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<SpringProfile name="production">
<Loggers>
<Logger name="org.springframework.boot.logging.log4j2" level="TRACE" />
</Loggers>
</SpringProfile>
</Configuration>
""")
private @interface WithProductionProfileXmlResource {
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 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.
@ -32,6 +32,9 @@ import ch.qos.logback.core.rolling.RollingPolicy;
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.ResourcesRoot;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
@ -43,11 +46,17 @@ import static org.assertj.core.api.Assertions.assertThat;
class LogbackConfigurationTests {
@Test
void consolePatternCanBeOverridden() throws JoranException {
@WithResource(name = "custom-console-log-pattern.xml", content = """
<configuration>
<property name="CONSOLE_LOG_PATTERN" value="foo" />
<include resource="org/springframework/boot/logging/logback/base.xml" />
</configuration>
""")
void consolePatternCanBeOverridden(@ResourcesRoot File resourcesRoot) throws JoranException {
JoranConfigurator configurator = new JoranConfigurator();
LoggerContext context = new LoggerContext();
configurator.setContext(context);
configurator.doConfigure(new File("src/test/resources/custom-console-log-pattern.xml"));
configurator.doConfigure(new File(resourcesRoot, "custom-console-log-pattern.xml"));
Appender<ILoggingEvent> appender = context.getLogger("ROOT").getAppender("CONSOLE");
assertThat(appender).isInstanceOf(ConsoleAppender.class);
Encoder<?> encoder = ((ConsoleAppender<?>) appender).getEncoder();
@ -56,11 +65,17 @@ class LogbackConfigurationTests {
}
@Test
void filePatternCanBeOverridden() throws JoranException {
@WithResource(name = "custom-file-log-pattern.xml", content = """
<configuration>
<property name="FILE_LOG_PATTERN" value="bar" />
<include resource="org/springframework/boot/logging/logback/base.xml" />
</configuration>
""")
void filePatternCanBeOverridden(@ResourcesRoot File resourcesRoot) throws JoranException {
JoranConfigurator configurator = new JoranConfigurator();
LoggerContext context = new LoggerContext();
configurator.setContext(context);
configurator.doConfigure(new File("src/test/resources/custom-file-log-pattern.xml"));
configurator.doConfigure(new File(resourcesRoot, "custom-file-log-pattern.xml"));
Appender<ILoggingEvent> appender = context.getLogger("ROOT").getAppender("FILE");
assertThat(appender).isInstanceOf(FileAppender.class);
Encoder<?> encoder = ((FileAppender<?>) appender).getEncoder();
@ -69,11 +84,17 @@ class LogbackConfigurationTests {
}
@Test
void defaultRollingFileNamePattern() throws JoranException {
@WithResource(name = "custom-file-log-pattern.xml", content = """
<configuration>
<property name="FILE_LOG_PATTERN" value="bar" />
<include resource="org/springframework/boot/logging/logback/base.xml" />
</configuration>
""")
void defaultRollingFileNamePattern(@ResourcesRoot File resourcesRoot) throws JoranException {
JoranConfigurator configurator = new JoranConfigurator();
LoggerContext context = new LoggerContext();
configurator.setContext(context);
configurator.doConfigure(new File("src/test/resources/custom-file-log-pattern.xml"));
configurator.doConfigure(new File(resourcesRoot, "custom-file-log-pattern.xml"));
Appender<ILoggingEvent> appender = context.getLogger("ROOT").getAppender("FILE");
assertThat(appender).isInstanceOf(RollingFileAppender.class);
RollingPolicy rollingPolicy = ((RollingFileAppender<?>) appender).getRollingPolicy();
@ -82,11 +103,17 @@ class LogbackConfigurationTests {
}
@Test
void customRollingFileNamePattern() throws JoranException {
@WithResource(name = "custom-file-log-pattern-with-fileNamePattern.xml", content = """
<configuration>
<property name="LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN" value="my.log.%d{yyyyMMdd}.%i.gz"/>
<include resource="org/springframework/boot/logging/logback/base.xml" />
</configuration>
""")
void customRollingFileNamePattern(@ResourcesRoot File resourcesRoot) throws JoranException {
JoranConfigurator configurator = new JoranConfigurator();
LoggerContext context = new LoggerContext();
configurator.setContext(context);
configurator.doConfigure(new File("src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml"));
configurator.doConfigure(new File(resourcesRoot, "custom-file-log-pattern-with-fileNamePattern.xml"));
Appender<ILoggingEvent> appender = context.getLogger("ROOT").getAppender("FILE");
assertThat(appender).isInstanceOf(RollingFileAppender.class);
RollingPolicy rollingPolicy = ((RollingFileAppender<?>) appender).getRollingPolicy();

View File

@ -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.
@ -17,6 +17,10 @@
package org.springframework.boot.logging.logback;
import java.io.File;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
@ -62,6 +66,7 @@ import org.springframework.boot.logging.LoggingSystemProperties;
import org.springframework.boot.logging.LoggingSystemProperty;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
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.core.convert.ConversionService;
@ -132,16 +137,30 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithResource(name = "include-defaults.xml", content = """
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%p] - %m%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
""")
void logbackDefaultsConfigurationDoesNotTriggerDeprecation(CapturedOutput output) {
initialize(this.initializationContext, "classpath:logback-include-defaults.xml", null);
initialize(this.initializationContext, "classpath:include-defaults.xml", null);
this.logger.info("Hello world");
assertThat(getLineWithText(output, "Hello world")).isEqualTo("[INFO] - Hello world");
assertThat(output.toString()).doesNotContain("WARN").doesNotContain("deprecated");
}
@Test
@WithIncludeBaseXmlResource
void logbackBaseConfigurationDoesNotTriggerDeprecation(CapturedOutput output) {
initialize(this.initializationContext, "classpath:logback-include-base.xml", null);
initialize(this.initializationContext, "classpath:include-base.xml", null);
this.logger.info("Hello world");
assertThat(getLineWithText(output, "Hello world")).contains(" INFO ").endsWith(": Hello world");
assertThat(output.toString()).doesNotContain("WARN").doesNotContain("deprecated");
@ -199,10 +218,10 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithNonDefaultXmlResource
void testNonDefaultConfigLocation(CapturedOutput output) {
this.loggingSystem.beforeInitialize();
initialize(this.initializationContext, "classpath:logback-nondefault.xml",
getLogFile(tmpDir() + "/tmp.log", null));
initialize(this.initializationContext, "classpath:nondefault.xml", getLogFile(tmpDir() + "/tmp.log", null));
this.logger.info("Hello world");
assertThat(output).doesNotContain("DEBUG")
.contains("Hello world")
@ -406,12 +425,13 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithIncludeBaseXmlResource
void testCleanHistoryOnStartPropertyWithXmlConfiguration() {
this.environment.setProperty("logging.file.clean-history-on-start", "true");
LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);
File file = new File(tmpDir(), "logback-test.log");
LogFile logFile = getLogFile(file.getPath(), null);
initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile);
initialize(loggingInitializationContext, "classpath:include-base.xml", logFile);
this.logger.info("Hello world");
assertThat(getLineWithText(file, "Hello world")).contains("INFO");
assertThat(getRollingPolicy().isCleanHistoryOnStart()).isTrue();
@ -444,12 +464,13 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithIncludeBaseXmlResource
void testMaxFileSizePropertyWithXmlConfiguration() {
this.environment.setProperty("logging.file.max-size", "100MB");
LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);
File file = new File(tmpDir(), "logback-test.log");
LogFile logFile = getLogFile(file.getPath(), null);
initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile);
initialize(loggingInitializationContext, "classpath:include-base.xml", logFile);
this.logger.info("Hello world");
assertThat(getLineWithText(file, "Hello world")).contains("INFO");
assertThat(ReflectionTestUtils.getField(getRollingPolicy(), "maxFileSize")).hasToString("100 MB");
@ -468,12 +489,13 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithIncludeBaseXmlResource
void testMaxHistoryPropertyWithXmlConfiguration() {
this.environment.setProperty("logging.file.max-history", "30");
LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);
File file = new File(tmpDir(), "logback-test.log");
LogFile logFile = getLogFile(file.getPath(), null);
initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile);
initialize(loggingInitializationContext, "classpath:include-base.xml", logFile);
this.logger.info("Hello world");
assertThat(getLineWithText(file, "Hello world")).contains("INFO");
assertThat(getRollingPolicy().getMaxHistory()).isEqualTo(30);
@ -506,13 +528,14 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithIncludeBaseXmlResource
void testTotalSizeCapPropertyWithXmlConfiguration() {
String expectedSize = "101 MB";
this.environment.setProperty("logging.file.total-size-cap", expectedSize);
LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);
File file = new File(tmpDir(), "logback-test.log");
LogFile logFile = getLogFile(file.getPath(), null);
initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile);
initialize(loggingInitializationContext, "classpath:include-base.xml", logFile);
this.logger.info("Hello world");
assertThat(getLineWithText(file, "Hello world")).contains("INFO");
assertThat(ReflectionTestUtils.getField(getRollingPolicy(), "totalSizeCap")).hasToString(expectedSize);
@ -546,12 +569,13 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithNonDefaultXmlResource
void initializeShouldSetSystemProperty() {
// gh-5491
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
LogFile logFile = getLogFile(tmpDir() + "/example.log", null, false);
initialize(this.initializationContext, "classpath:logback-nondefault.xml", logFile);
initialize(this.initializationContext, "classpath:nondefault.xml", logFile);
assertThat(System.getProperty(LoggingSystemProperty.LOG_FILE.getEnvironmentVariableName()))
.endsWith("example.log");
}
@ -698,9 +722,23 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test // gh-33610
@WithResource(name = "springprofile-in-root.xml", content = """
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%property{LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>
</encoder>
</appender>
<root level="INFO">
<springProfile name="profile">
<appender-ref ref="CONSOLE"/>
</springProfile>
</root>
</configuration>
""")
void springProfileIfNestedWithinSecondPhaseElementSanityChecker(CapturedOutput output) {
this.loggingSystem.beforeInitialize();
initialize(this.initializationContext, "classpath:logback-springprofile-in-root.xml", null);
initialize(this.initializationContext, "classpath:springprofile-in-root.xml", null);
this.logger.info("Hello world");
assertThat(output).contains("<springProfile> elements cannot be nested within an");
}
@ -756,9 +794,10 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithIncludeBaseXmlResource
void correlationLoggingToConsoleWhenUsingXmlConfiguration(CapturedOutput output) {
this.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, "true");
initialize(this.initializationContext, "classpath:logback-include-base.xml", null);
initialize(this.initializationContext, "classpath:include-base.xml", null);
MDC.setContextMap(Map.of("traceId", "01234567890123456789012345678901", "spanId", "0123456789012345"));
this.logger.info("Hello world");
assertThat(getLineWithText(output, "Hello world"))
@ -766,11 +805,12 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithIncludeBaseXmlResource
void correlationLoggingToFileWhenUsingFileConfiguration() {
this.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, "true");
File file = new File(tmpDir(), "logback-test.log");
LogFile logFile = getLogFile(file.getPath(), null);
initialize(this.initializationContext, "classpath:logback-include-base.xml", logFile);
initialize(this.initializationContext, "classpath:include-base.xml", logFile);
MDC.setContextMap(Map.of("traceId", "01234567890123456789012345678901", "spanId", "0123456789012345"));
this.logger.info("Hello world");
assertThat(getLineWithText(file, "Hello world"))
@ -834,30 +874,55 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithResource(name = "broken.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsolAppender">
<encoder>
<pattern>${LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
""")
void whenConfigurationErrorIsDetectedUnderlyingCausesAreIncludedAsSuppressedExceptions() {
this.loggingSystem.beforeInitialize();
assertThatIllegalStateException()
.isThrownBy(() -> initialize(this.initializationContext, "classpath:logback-broken.xml",
.isThrownBy(() -> initialize(this.initializationContext, "classpath:broken.xml",
getLogFile(tmpDir() + "/tmp.log", null)))
.satisfies((ex) -> assertThat(ex.getSuppressed())
.hasAtLeastOneElementOfType(DynamicClassLoadingException.class));
}
@Test
@WithResource(name = "invalid-format.txt", content = "Not XML")
void whenConfigLocationIsNotXmlThenIllegalArgumentExceptionShouldBeThrown() {
this.loggingSystem.beforeInitialize();
assertThatIllegalStateException()
.isThrownBy(() -> initialize(this.initializationContext, "classpath:logback-invalid-format.txt",
.isThrownBy(() -> initialize(this.initializationContext, "classpath:invalid-format.txt",
getLogFile(tmpDir() + "/tmp.log", null)))
.satisfies((ex) -> assertThat(ex.getCause()).isInstanceOf(JoranException.class)
.hasMessageStartingWith("Problem parsing XML document. See previously reported errors"));
}
@Test
@WithResource(name = "without-extension", content = """
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
""")
void whenConfigLocationIsXmlFileWithoutExtensionShouldWork(CapturedOutput output) {
this.loggingSystem.beforeInitialize();
initialize(this.initializationContext, "classpath:logback-without-extension",
getLogFile(tmpDir() + "/tmp.log", null));
initialize(this.initializationContext, "classpath:without-extension", getLogFile(tmpDir() + "/tmp.log", null));
this.logger.info("No extension and works!");
assertThat(output.toString()).contains("No extension and works!");
}
@ -895,11 +960,12 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
@Test
@WithNonDefaultXmlResource
void applyingSystemPropertiesDoesNotCauseUnwantedStatusWarnings(CapturedOutput output) {
this.loggingSystem.beforeInitialize();
this.environment.getPropertySources()
.addFirst(new MapPropertySource("test", Map.of("logging.pattern.console", "[CONSOLE]%m")));
this.loggingSystem.initialize(this.initializationContext, "classpath:logback-nondefault.xml", null);
this.loggingSystem.initialize(this.initializationContext, "classpath:nondefault.xml", null);
assertThat(output).doesNotContain("WARN");
}
@ -935,4 +1001,33 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
return (SizeAndTimeBasedRollingPolicy<?>) getFileAppender().getRollingPolicy();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "include-base.xml", content = """
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
</configuration>
""")
private @interface WithIncludeBaseXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "nondefault.xml", content = """
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%property{LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
""")
private @interface WithNonDefaultXmlResource {
}
}

View File

@ -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,11 @@
package org.springframework.boot.logging.logback;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import ch.qos.logback.classic.BasicConfigurator;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
@ -30,6 +35,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.logging.LoggingInitializationContext;
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.mock.env.MockEnvironment;
@ -77,6 +84,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithProductionProfileXmlResource
void profileActive() throws Exception {
this.environment.setActiveProfiles("production");
initialize("production-profile.xml");
@ -85,6 +93,20 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithResource(name = "profile-in-include.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<include file="${resourceRoot}/include-with-profile.xml"/>
</configuration>
""")
@WithResource(name = "include-with-profile.xml", content = """
<included>
<springProfile name="production">
<logger name="org.springframework.boot.logging.logback" level="TRACE"/>
</springProfile>
</included>
""")
void profileInIncludeActive() throws Exception {
this.environment.setActiveProfiles("production");
initialize("profile-in-include.xml");
@ -93,6 +115,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithMultiProfileNamesXmlResource
void multipleNamesFirstProfileActive() throws Exception {
this.environment.setActiveProfiles("production");
initialize("multi-profile-names.xml");
@ -101,6 +124,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithMultiProfileNamesXmlResource
void multipleNamesSecondProfileActive() throws Exception {
this.environment.setActiveProfiles("test");
initialize("multi-profile-names.xml");
@ -109,6 +133,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithProductionProfileXmlResource
void profileNotActive() throws Exception {
initialize("production-profile.xml");
this.logger.trace("Hello");
@ -116,6 +141,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithProfileExpressionXmlResource
void profileExpressionMatchFirst() throws Exception {
this.environment.setActiveProfiles("production");
initialize("profile-expression.xml");
@ -124,6 +150,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithProfileExpressionXmlResource
void profileExpressionMatchSecond() throws Exception {
this.environment.setActiveProfiles("test");
initialize("profile-expression.xml");
@ -132,6 +159,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithProfileExpressionXmlResource
void profileExpressionNoMatch() throws Exception {
this.environment.setActiveProfiles("development");
initialize("profile-expression.xml");
@ -140,26 +168,31 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithNestedXmlResource
void profileNestedActiveActive() throws Exception {
doTestNestedProfile(true, "outer", "inner");
}
@Test
@WithNestedXmlResource
void profileNestedActiveNotActive() throws Exception {
doTestNestedProfile(false, "outer");
}
@Test
@WithNestedXmlResource
void profileNestedNotActiveActive() throws Exception {
doTestNestedProfile(false, "inner");
}
@Test
@WithNestedXmlResource
void profileNestedNotActiveNotActive() throws Exception {
doTestNestedProfile(false);
}
@Test
@WithPropertyXmlResource
void springProperty() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "my.example-property=test");
initialize("property.xml");
@ -167,6 +200,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithPropertyXmlResource
void relaxedSpringProperty() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "my.EXAMPLE_PROPERTY=test");
ConfigurationPropertySources.attach(this.environment);
@ -175,30 +209,35 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithPropertyXmlResource
void springPropertyNoValue() throws Exception {
initialize("property.xml");
assertThat(this.context.getProperty("SIMPLE")).isNull();
}
@Test
@WithPropertyXmlResource
void relaxedSpringPropertyNoValue() throws Exception {
initialize("property.xml");
assertThat(this.context.getProperty("MINE")).isNull();
}
@Test
@WithPropertyDefaultValueXmlResource
void springPropertyWithDefaultValue() throws Exception {
initialize("property-default-value.xml");
assertThat(this.context.getProperty("SIMPLE")).isEqualTo("foo");
}
@Test
@WithPropertyDefaultValueXmlResource
void relaxedSpringPropertyWithDefaultValue() throws Exception {
initialize("property-default-value.xml");
assertThat(this.context.getProperty("MINE")).isEqualTo("bar");
}
@Test
@WithPropertyInIfXmlResource
void springPropertyInIfWhenTrue() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "my.example-property=true");
initialize("property-in-if.xml");
@ -206,6 +245,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithPropertyInIfXmlResource
void springPropertyInIfWhenFalse() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "my.example-property=false");
initialize("property-in-if.xml");
@ -213,6 +253,19 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithResource(name = "property-in-include.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<include file="${resourceRoot}/include-with-property.xml"/>
</configuration>
""")
@WithResource(name = "include-with-property.xml", content = """
<included>
<springProperty scope="context" name="MINE" source="my.example-property" defaultValue="default-test"/>
</included>
""")
@ClassPathExclusions
void springPropertyInInclude() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "my.example-property=test");
initialize("property-in-include.xml");
@ -220,6 +273,7 @@ class SpringBootJoranConfiguratorTests {
}
@Test
@WithPropertyXmlResource
void addsAotContributionToContextDuringAotProcessing() throws Exception {
withSystemProperty("spring.aot.processing", "true", () -> {
initialize("property.xml");
@ -253,7 +307,8 @@ class SpringBootJoranConfiguratorTests {
private void initialize(String config) throws JoranException {
this.configurator.setContext(this.context);
this.configurator.doConfigure(getClass().getResourceAsStream(config));
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
this.configurator.doConfigure(contextClassLoader.getResource(config));
}
private interface Action {
@ -262,4 +317,112 @@ class SpringBootJoranConfiguratorTests {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "property-default-value.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<springProperty scope="context" name="SIMPLE" source="testpropertyfoobar" defaultValue="foo"/>
<springProperty scope="context" name="MINE" source="my.example-property" defaultValue="bar"/>
</configuration>
""")
private @interface WithPropertyDefaultValueXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "property-in-if.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<springProperty scope="context" name="MINE" source="my.example-property"/>
<if condition='property("MINE").contains("true")'>
<then>
<variable scope="context" name="MYCHECK" value="i-was-included"/>
</then>
</if>
</configuration>
""")
private @interface WithPropertyInIfXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "property.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<springProperty scope="context" name="SIMPLE" source="testpropertyfoobar"/>
<springProperty scope="context" name="MINE" source="my.example-property"/>
</configuration>
""")
private @interface WithPropertyXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "profile-expression.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<springProfile name="production | test">
<logger name="org.springframework.boot.logging.logback" level="TRACE"/>
</springProfile>
</configuration>
""")
private @interface WithProfileExpressionXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "production-profile.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<springProfile name="production">
<logger name="org.springframework.boot.logging.logback" level="TRACE"/>
</springProfile>
</configuration>
""")
private @interface WithProductionProfileXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "nested.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<springProfile name="outer">
<springProfile name="inner">
<logger name="org.springframework.boot.logging.logback" level="TRACE"/>
</springProfile>
</springProfile>
</configuration>
""")
private @interface WithNestedXmlResource {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "multi-profile-names.xml", content = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<springProfile name="production, test">
<logger name="org.springframework.boot.logging.logback" level="TRACE"/>
</springProfile>
</configuration>
""")
private @interface WithMultiProfileNamesXmlResource {
}
}

View File

@ -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.
@ -52,6 +52,8 @@ import org.springframework.boot.ssl.jks.JksSslStoreBundle;
import org.springframework.boot.ssl.jks.JksSslStoreDetails;
import org.springframework.boot.ssl.pem.PemSslStoreBundle;
import org.springframework.boot.ssl.pem.PemSslStoreDetails;
import org.springframework.boot.testsupport.classpath.resources.ResourcePath;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.web.server.Ssl;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.codec.StringDecoder;
@ -156,91 +158,107 @@ class NettyRSocketServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void tcpTransportBasicSslFromClassPath() {
testBasicSslWithKeyStore("classpath:test.jks", "password", Transport.TCP);
}
@Test
void tcpTransportBasicSslFromFileSystem() {
testBasicSslWithKeyStore("src/test/resources/test.jks", "password", Transport.TCP);
@WithPackageResources("test.jks")
void tcpTransportBasicSslFromFileSystem(@ResourcePath("test.jks") String keyStore) {
testBasicSslWithKeyStore(keyStore, "password", Transport.TCP);
}
@Test
@WithPackageResources("test.jks")
void websocketTransportBasicSslFromClassPath() {
testBasicSslWithKeyStore("classpath:test.jks", "password", Transport.WEBSOCKET);
}
@Test
void websocketTransportBasicSslFromFileSystem() {
testBasicSslWithKeyStore("src/test/resources/test.jks", "password", Transport.WEBSOCKET);
@WithPackageResources("test.jks")
void websocketTransportBasicSslFromFileSystem(@ResourcePath("test.jks") String keyStore) {
testBasicSslWithKeyStore(keyStore, "password", Transport.WEBSOCKET);
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void tcpTransportBasicSslCertificateFromClassPath() {
testBasicSslWithPemCertificate("classpath:test-cert.pem", "classpath:test-key.pem", "classpath:test-cert.pem",
Transport.TCP);
}
@Test
void tcpTransportBasicSslCertificateFromFileSystem() {
testBasicSslWithPemCertificate("src/test/resources/test-cert.pem", "src/test/resources/test-key.pem",
"src/test/resources/test-cert.pem", Transport.TCP);
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void tcpTransportBasicSslCertificateFromFileSystem(@ResourcePath("test-cert.pem") String testCert,
@ResourcePath("test-key.pem") String testKey) {
testBasicSslWithPemCertificate(testCert, testKey, testCert, Transport.TCP);
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void websocketTransportBasicSslCertificateFromClassPath() {
testBasicSslWithPemCertificate("classpath:test-cert.pem", "classpath:test-key.pem", "classpath:test-cert.pem",
Transport.WEBSOCKET);
}
@Test
void websocketTransportBasicSslCertificateFromFileSystem() {
testBasicSslWithPemCertificate("src/test/resources/test-cert.pem", "src/test/resources/test-key.pem",
"src/test/resources/test-cert.pem", Transport.WEBSOCKET);
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void websocketTransportBasicSslCertificateFromFileSystem(@ResourcePath("test-cert.pem") String testCert,
@ResourcePath("test-key.pem") String testKey) {
testBasicSslWithPemCertificate(testCert, testKey, testCert, Transport.WEBSOCKET);
}
@Test
@WithPackageResources("test.jks")
void tcpTransportBasicSslFromClassPathWithBundle() {
testBasicSslWithKeyStoreFromBundle("classpath:test.jks", "password", Transport.TCP);
}
@Test
void tcpTransportBasicSslFromFileSystemWithBundle() {
testBasicSslWithKeyStoreFromBundle("src/test/resources/test.jks", "password", Transport.TCP);
@WithPackageResources("test.jks")
void tcpTransportBasicSslFromFileSystemWithBundle(@ResourcePath("test.jks") String keyStore) {
testBasicSslWithKeyStoreFromBundle(keyStore, "password", Transport.TCP);
}
@Test
@WithPackageResources("test.jks")
void websocketTransportBasicSslFromClassPathWithBundle() {
testBasicSslWithKeyStoreFromBundle("classpath:test.jks", "password", Transport.WEBSOCKET);
}
@Test
void websocketTransportBasicSslFromFileSystemWithBundle() {
testBasicSslWithKeyStoreFromBundle("src/test/resources/test.jks", "password", Transport.WEBSOCKET);
@WithPackageResources("test.jks")
void websocketTransportBasicSslFromFileSystemWithBundle(@ResourcePath("test.jks") String keyStore) {
testBasicSslWithKeyStoreFromBundle(keyStore, "password", Transport.WEBSOCKET);
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void tcpTransportBasicSslCertificateFromClassPathWithBundle() {
testBasicSslWithPemCertificateFromBundle("classpath:test-cert.pem", "classpath:test-key.pem",
"classpath:test-cert.pem", Transport.TCP);
}
@Test
void tcpTransportBasicSslCertificateFromFileSystemWithBundle() {
testBasicSslWithPemCertificateFromBundle("src/test/resources/test-cert.pem", "src/test/resources/test-key.pem",
"src/test/resources/test-cert.pem", Transport.TCP);
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void tcpTransportBasicSslCertificateFromFileSystemWithBundle(@ResourcePath("test-cert.pem") String testCert,
@ResourcePath("test-key.pem") String testKey) {
testBasicSslWithPemCertificateFromBundle(testCert, testKey, testCert, Transport.TCP);
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void websocketTransportBasicSslCertificateFromClassPathWithBundle() {
testBasicSslWithPemCertificateFromBundle("classpath:test-cert.pem", "classpath:test-key.pem",
"classpath:test-cert.pem", Transport.WEBSOCKET);
}
@Test
void websocketTransportBasicSslCertificateFromFileSystemWithBundle() {
testBasicSslWithPemCertificateFromBundle("src/test/resources/test-cert.pem", "src/test/resources/test-key.pem",
"src/test/resources/test-cert.pem", Transport.WEBSOCKET);
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void websocketTransportBasicSslCertificateFromFileSystemWithBundle(@ResourcePath("test-cert.pem") String testCert,
@ResourcePath("test-key.pem") String testKey) {
testBasicSslWithPemCertificateFromBundle(testCert, testKey, testCert, Transport.WEBSOCKET);
}
private void checkEchoRequest() {
@ -318,7 +336,7 @@ class NettyRSocketServerFactoryTests {
NettyRSocketServerFactory factory = getFactory();
factory.setTransport(Transport.TCP);
Ssl ssl = new Ssl();
ssl.setKeyStore("classpath:test.jks");
ssl.setKeyStore("classpath:org/springframework/boot/rsocket/netty/test.jks");
ssl.setKeyPassword("password");
factory.setSsl(ssl);
this.server = factory.create(new EchoRequestResponseAcceptor());

View File

@ -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,10 +16,15 @@
package org.springframework.boot.sql.init;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.dao.DataAccessException;
import static org.assertj.core.api.Assertions.assertThat;
@ -35,6 +40,8 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractScriptDatabaseInitializer> {
@Test
@WithSchemaSqlResource
@WithDataSqlResource
void whenDatabaseIsInitializedThenSchemaAndDataScriptsAreApplied() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setSchemaLocations(Arrays.asList("schema.sql"));
@ -55,6 +62,7 @@ public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractS
}
@Test
@WithDataSqlResource
void whenContinueOnErrorIsFalseThenInitializationFailsOnError() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setDataLocations(Arrays.asList("data.sql"));
@ -64,6 +72,7 @@ public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractS
}
@Test
@WithDataSqlResource
void whenContinueOnErrorIsTrueThenInitializationDoesNotFailOnError() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setContinueOnError(true);
@ -112,6 +121,8 @@ public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractS
}
@Test
@WithSchemaSqlResource
@WithDataSqlResource
void whenModeIsNeverThenEmbeddedDatabaseIsNotInitialized() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setSchemaLocations(Arrays.asList("schema.sql"));
@ -123,6 +134,8 @@ public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractS
}
@Test
@WithSchemaSqlResource
@WithDataSqlResource
void whenModeIsNeverThenStandaloneDatabaseIsNotInitialized() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setSchemaLocations(Arrays.asList("schema.sql"));
@ -134,6 +147,8 @@ public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractS
}
@Test
@WithSchemaSqlResource
@WithDataSqlResource
void whenModeIsEmbeddedThenEmbeddedDatabaseIsInitialized() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setSchemaLocations(Arrays.asList("schema.sql"));
@ -145,6 +160,8 @@ public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractS
}
@Test
@WithSchemaSqlResource
@WithDataSqlResource
void whenModeIsEmbeddedThenStandaloneDatabaseIsNotInitialized() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setSchemaLocations(Arrays.asList("schema.sql"));
@ -156,6 +173,8 @@ public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractS
}
@Test
@WithSchemaSqlResource
@WithDataSqlResource
void whenModeIsAlwaysThenEmbeddedDatabaseIsInitialized() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setSchemaLocations(Arrays.asList("schema.sql"));
@ -167,6 +186,8 @@ public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractS
}
@Test
@WithSchemaSqlResource
@WithDataSqlResource
void whenModeIsAlwaysThenStandaloneDatabaseIsInitialized() {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
settings.setSchemaLocations(Arrays.asList("schema.sql"));
@ -195,4 +216,23 @@ public abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractS
protected abstract void assertDatabaseAccessed(boolean accessed, T initializer);
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@WithResource(name = "schema.sql", content = """
CREATE TABLE EXAMPLE (
id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(30)
);
""")
protected @interface WithSchemaSqlResource {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@WithResource(name = "data.sql", content = "INSERT INTO EXAMPLE VALUES (1, 'Andy');")
protected @interface WithDataSqlResource {
}
}

View File

@ -25,6 +25,7 @@ import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.io.ApplicationResourceLoader;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.testsupport.ssl.MockPkcs11Security;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
@ -77,6 +78,7 @@ class JksSslStoreBundleTests {
}
@Test
@WithPackageResources("test.jks")
void whenHasKeyStoreLocation() {
JksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation("classpath:test.jks")
.withPassword("secret");
@ -86,6 +88,7 @@ class JksSslStoreBundleTests {
}
@Test
@WithPackageResources("test.jks")
void getTrustStoreWithLocations() {
JksSslStoreDetails keyStoreDetails = null;
JksSslStoreDetails trustStoreDetails = JksSslStoreDetails.forLocation("classpath:test.jks")
@ -95,6 +98,7 @@ class JksSslStoreBundleTests {
}
@Test
@WithPackageResources("test.jks")
void whenHasKeyStoreType() {
JksSslStoreDetails keyStoreDetails = new JksSslStoreDetails("jks", null, "classpath:test.jks", "secret");
JksSslStoreDetails trustStoreDetails = null;
@ -103,6 +107,7 @@ class JksSslStoreBundleTests {
}
@Test
@WithPackageResources("test.jks")
void whenHasTrustStoreType() {
JksSslStoreDetails keyStoreDetails = null;
JksSslStoreDetails trustStoreDetails = new JksSslStoreDetails("jks", null, "classpath:test.jks", "secret");
@ -111,6 +116,7 @@ class JksSslStoreBundleTests {
}
@Test
@WithPackageResources("test.jks")
void whenHasKeyStoreProvider() {
JksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(null, "com.example.KeyStoreProvider",
"classpath:test.jks", "secret");
@ -120,6 +126,7 @@ class JksSslStoreBundleTests {
}
@Test
@WithPackageResources("test.jks")
void whenHasTrustStoreProvider() {
JksSslStoreDetails trustStoreDetails = new JksSslStoreDetails(null, "com.example.KeyStoreProvider",
"classpath:test.jks", "secret");
@ -137,6 +144,7 @@ class JksSslStoreBundleTests {
}
@Test
@WithPackageResources({ "test.p12", "test.jks" })
void whenLocationsAreBase64Encoded() throws IOException {
JksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(encodeFileContent("classpath:test.p12"))
.withPassword("secret");
@ -169,6 +177,7 @@ class JksSslStoreBundleTests {
}
@Test
@WithPackageResources("test.jks")
void usesResourceLoader() {
JksSslStoreDetails keyStoreDetails = null;
JksSslStoreDetails trustStoreDetails = new JksSslStoreDetails("jks", null, "classpath:test.jks", "secret");

View File

@ -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.
@ -21,6 +21,7 @@ import java.io.UncheckedIOException;
import org.junit.jupiter.api.Test;
import org.springframework.boot.io.ApplicationResourceLoader;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
@ -37,6 +38,7 @@ import static org.mockito.Mockito.spy;
class LoadedPemSslStoreTests {
@Test
@WithPackageResources("test-key.pem")
void certificatesAreLoadedLazily() {
PemSslStoreDetails details = PemSslStoreDetails.forCertificate("classpath:missing-test-cert.pem")
.withPrivateKey("classpath:test-key.pem");
@ -45,6 +47,7 @@ class LoadedPemSslStoreTests {
}
@Test
@WithPackageResources("test-cert.pem")
void privateKeyIsLoadedLazily() {
PemSslStoreDetails details = PemSslStoreDetails.forCertificate("classpath:test-cert.pem")
.withPrivateKey("classpath:missing-test-key.pem");
@ -53,6 +56,7 @@ class LoadedPemSslStoreTests {
}
@Test
@WithPackageResources("test-key.pem")
void withAliasIsLazy() {
PemSslStoreDetails details = PemSslStoreDetails.forCertificate("classpath:missing-test-cert.pem")
.withPrivateKey("classpath:test-key.pem");
@ -61,6 +65,7 @@ class LoadedPemSslStoreTests {
}
@Test
@WithPackageResources("test-key.pem")
void withPasswordIsLazy() {
PemSslStoreDetails details = PemSslStoreDetails.forCertificate("classpath:missing-test-cert.pem")
.withPrivateKey("classpath:test-key.pem");
@ -69,6 +74,7 @@ class LoadedPemSslStoreTests {
}
@Test
@WithPackageResources("test-cert.pem")
void usesResourceLoader() {
PemSslStoreDetails details = PemSslStoreDetails.forCertificate("classpath:test-cert.pem");
ResourceLoader resourceLoader = spy(new DefaultResourceLoader());

View File

@ -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 java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
@ -35,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class PemCertificateParserTests {
@Test
@WithPackageResources("test-cert.pem")
void parseCertificate() throws Exception {
List<X509Certificate> certificates = PemCertificateParser.parse(read("test-cert.pem"));
assertThat(certificates).isNotNull();
@ -43,6 +45,7 @@ class PemCertificateParserTests {
}
@Test
@WithPackageResources("test-cert-chain.pem")
void parseCertificateChain() throws Exception {
List<X509Certificate> certificates = PemCertificateParser.parse(read("test-cert-chain.pem"));
assertThat(certificates).isNotNull();

View File

@ -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.
@ -26,6 +26,8 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.io.ApplicationResourceLoader;
import org.springframework.boot.testsupport.classpath.resources.ResourcePath;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
@ -51,6 +53,7 @@ class PemContentTests {
}
@Test
@WithPackageResources("test-cert-chain.pem")
void getCertificateReturnsCertificates() throws Exception {
PemContent content = PemContent.load(contentFromClasspath("/test-cert-chain.pem"),
new ApplicationResourceLoader());
@ -69,9 +72,9 @@ class PemContentTests {
}
@Test
@WithPackageResources("dsa.key")
void getPrivateKeyReturnsPrivateKey() throws Exception {
PemContent content = PemContent.load(contentFromClasspath("/org/springframework/boot/web/server/pkcs8/dsa.key"),
new ApplicationResourceLoader());
PemContent content = PemContent.load(contentFromClasspath("dsa.key"), new ApplicationResourceLoader());
PrivateKey privateKey = content.getPrivateKey();
assertThat(privateKey).isNotNull();
assertThat(privateKey.getFormat()).isEqualTo("PKCS#8");
@ -122,6 +125,7 @@ class PemContentTests {
}
@Test
@WithPackageResources("test-cert.pem")
void loadWithStringWhenClasspathLocationReturnsContent() throws IOException {
String actual = PemContent.load("classpath:test-cert.pem", new ApplicationResourceLoader()).toString();
String expected = contentFromClasspath("test-cert.pem");
@ -129,21 +133,24 @@ class PemContentTests {
}
@Test
void loadWithStringWhenFileLocationReturnsContent() throws IOException {
String actual = PemContent.load("src/test/resources/test-cert.pem", new ApplicationResourceLoader()).toString();
@WithPackageResources("test-cert.pem")
void loadWithStringWhenFileLocationReturnsContent(@ResourcePath("test-cert.pem") String testCert)
throws IOException {
String actual = PemContent.load(testCert, new ApplicationResourceLoader()).toString();
String expected = contentFromClasspath("test-cert.pem");
assertThat(actual).isEqualTo(expected);
}
@Test
void loadWithPathReturnsContent() throws IOException {
Path path = Path.of("src/test/resources/test-cert.pem");
String actual = PemContent.load(path).toString();
@WithPackageResources("test-cert.pem")
void loadWithPathReturnsContent(@ResourcePath("test-cert.pem") Path testCert) throws IOException {
String actual = PemContent.load(testCert).toString();
String expected = contentFromClasspath("test-cert.pem");
assertThat(actual).isEqualTo(expected);
}
@Test
@WithPackageResources("test-cert.pem")
void loadWithResourceLoaderUsesResourceLoader() throws IOException {
ResourceLoader resourceLoader = spy(new DefaultResourceLoader());
PemContent.load("classpath:test-cert.pem", resourceLoader);

View File

@ -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.
@ -47,36 +47,25 @@ class PemPrivateKeyParserTests {
"rsa.key, RSA",
"rsa-pss.key, RSASSA-PSS"
})
// @formatter:on
// @formatter:on
void shouldParseTraditionalPkcs8(String file, String algorithm) throws IOException {
PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file));
PrivateKey privateKey = PemPrivateKeyParser.parse(read("pkcs8/" + file));
assertThat(privateKey).isNotNull();
assertThat(privateKey.getFormat()).isEqualTo("PKCS#8");
assertThat(privateKey.getAlgorithm()).isEqualTo(algorithm);
}
@ParameterizedTest
// @formatter:off
@CsvSource({
"rsa.key, RSA"
})
// @formatter:on
void shouldParseTraditionalPkcs1(String file, String algorithm) throws IOException {
PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs1/" + file));
@Test
void shouldParseTraditionalPkcs1() throws IOException {
PrivateKey privateKey = PemPrivateKeyParser.parse(read("pkcs1/rsa.key"));
assertThat(privateKey).isNotNull();
assertThat(privateKey.getFormat()).isEqualTo("PKCS#8");
assertThat(privateKey.getAlgorithm()).isEqualTo(algorithm);
assertThat(privateKey.getAlgorithm()).isEqualTo("RSA");
}
@ParameterizedTest
// @formatter:off
@ValueSource(strings = {
"dsa.key"
})
// @formatter:on
void shouldNotParseUnsupportedTraditionalPkcs1(String file) {
assertThatIllegalStateException()
.isThrownBy(() -> PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs1/" + file)))
@Test
void shouldNotParseUnsupportedTraditionalPkcs1() {
assertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read("pkcs1/dsa.key")))
.withMessageContaining("Missing private key or unrecognized format");
}
@ -94,9 +83,9 @@ class PemPrivateKeyParserTests {
"secp384r1.key, secp384r1, 1.3.132.0.34",
"secp521r1.key, secp521r1, 1.3.132.0.35"
})
// @formatter:on
// @formatter:on
void shouldParseEcPkcs8(String file, String curveName, String oid) throws IOException {
PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file));
PrivateKey privateKey = PemPrivateKeyParser.parse(read("pkcs8/" + file));
assertThat(privateKey).isNotNull();
assertThat(privateKey.getFormat()).isEqualTo("PKCS#8");
assertThat(privateKey.getAlgorithm()).isEqualTo("EC");
@ -115,8 +104,7 @@ class PemPrivateKeyParserTests {
})
// @formatter:on
void shouldNotParseUnsupportedEcPkcs8(String file) {
assertThatIllegalStateException()
.isThrownBy(() -> PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file)))
assertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read("pkcs8/" + file)))
.withMessageContaining("Missing private key or unrecognized format");
}
@ -128,7 +116,7 @@ class PemPrivateKeyParserTests {
})
// @formatter:on
void shouldParseEdDsaPkcs8(String file) throws IOException {
PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file));
PrivateKey privateKey = PemPrivateKeyParser.parse(read("pkcs8/" + file));
assertThat(privateKey).isNotNull();
assertThat(privateKey.getFormat()).isEqualTo("PKCS#8");
assertThat(privateKey.getAlgorithm()).isEqualTo("EdDSA");
@ -142,7 +130,7 @@ class PemPrivateKeyParserTests {
})
// @formatter:on
void shouldParseXdhPkcs8(String file) throws IOException {
PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file));
PrivateKey privateKey = PemPrivateKeyParser.parse(read("pkcs8/" + file));
assertThat(privateKey).isNotNull();
assertThat(privateKey.getFormat()).isEqualTo("PKCS#8");
assertThat(privateKey.getAlgorithm()).isEqualTo("XDH");
@ -164,7 +152,7 @@ class PemPrivateKeyParserTests {
})
// @formatter:on
void shouldParseEcSec1(String file, String curveName, String oid) throws IOException {
PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/sec1/" + file));
PrivateKey privateKey = PemPrivateKeyParser.parse(read("sec1/" + file));
assertThat(privateKey).isNotNull();
assertThat(privateKey.getFormat()).isEqualTo("PKCS#8");
assertThat(privateKey.getAlgorithm()).isEqualTo("EC");
@ -183,14 +171,13 @@ class PemPrivateKeyParserTests {
})
// @formatter:on
void shouldNotParseUnsupportedEcSec1(String file) {
assertThatIllegalStateException()
.isThrownBy(() -> PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/sec1/" + file)))
assertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read("sec1/" + file)))
.withMessageContaining("Missing private key or unrecognized format");
}
@Test
void parseWithNonKeyTextWillThrowException() {
assertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read("test-banner.txt")));
assertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read("file.txt")));
}
@ParameterizedTest
@ -208,8 +195,7 @@ class PemPrivateKeyParserTests {
// openssl pkcs8 -topk8 -in <input file> -out <output file> -v2 <algorithm>
// -passout pass:test
// where <algorithm> is aes128 or aes256
PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file),
"test");
PrivateKey privateKey = PemPrivateKeyParser.parse(read("pkcs8/" + file), "test");
assertThat(privateKey).isNotNull();
assertThat(privateKey.getFormat()).isEqualTo("PKCS#8");
assertThat(privateKey.getAlgorithm()).isEqualTo(algorithm);
@ -221,8 +207,7 @@ class PemPrivateKeyParserTests {
// openssl pkcs8 -topk8 -in rsa.key -out rsa-des-ede3-cbc.key -v2 des3 -passout
// pass:test
assertThatIllegalStateException()
.isThrownBy(() -> PemPrivateKeyParser
.parse(read("org/springframework/boot/web/server/pkcs8/rsa-des-ede3-cbc.key"), "test"))
.isThrownBy(() -> PemPrivateKeyParser.parse(read("pkcs8/rsa-des-ede3-cbc.key"), "test"))
.isInstanceOf(IllegalStateException.class)
.withMessageContaining("Error decrypting private key");
}
@ -233,8 +218,7 @@ class PemPrivateKeyParserTests {
// openssl pkcs8 -topk8 -in rsa.key -out rsa-des-ede3-cbc.key -scrypt -passout
// pass:test
assertThatIllegalStateException()
.isThrownBy(() -> PemPrivateKeyParser
.parse(read("org/springframework/boot/web/server/pkcs8/rsa-scrypt.key"), "test"))
.isThrownBy(() -> PemPrivateKeyParser.parse(read("pkcs8/rsa-scrypt.key"), "test"))
.withMessageContaining("Error decrypting private key");
}
@ -244,8 +228,7 @@ class PemPrivateKeyParserTests {
// openssl ecparam -genkey -name prime256v1 | openssl ec -aes-128-cbc -out
// prime256v1-aes-128-cbc.key
assertThatIllegalStateException()
.isThrownBy(() -> PemPrivateKeyParser
.parse(read("org/springframework/boot/web/server/sec1/prime256v1-aes-128-cbc.key"), "test"))
.isThrownBy(() -> PemPrivateKeyParser.parse(read("sec1/prime256v1-aes-128-cbc.key"), "test"))
.withMessageContaining("Missing private key or unrecognized format");
}
@ -254,13 +237,13 @@ class PemPrivateKeyParserTests {
// created with:
// openssl genrsa -aes-256-cbc -out rsa-aes-256-cbc.key
assertThatIllegalStateException()
.isThrownBy(() -> PemPrivateKeyParser
.parse(read("org/springframework/boot/web/server/pkcs1/rsa-aes-256-cbc.key"), "test"))
.isThrownBy(() -> PemPrivateKeyParser.parse(read("pkcs1/rsa-aes-256-cbc.key"), "test"))
.withMessageContaining("Missing private key or unrecognized format");
}
private String read(String path) throws IOException {
return new ClassPathResource(path).getContentAsString(StandardCharsets.UTF_8);
return new ClassPathResource("org/springframework/boot/ssl/pem/" + path)
.getContentAsString(StandardCharsets.UTF_8);
}
}

View File

@ -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.
@ -24,6 +24,7 @@ import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.util.function.ThrowingConsumer;
import static org.assertj.core.api.Assertions.assertThat;
@ -120,6 +121,7 @@ class PemSslStoreBundleTests {
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void createWithDetailsWhenHasKeyStoreDetailsCertAndKey() {
PemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate("classpath:test-cert.pem")
.withPrivateKey("classpath:test-key.pem");
@ -130,9 +132,10 @@ class PemSslStoreBundleTests {
}
@Test
@WithPackageResources({ "test-cert.pem", "pkcs8/key-rsa-encrypted.pem" })
void createWithDetailsWhenHasKeyStoreDetailsCertAndEncryptedKey() {
PemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate("classpath:test-cert.pem")
.withPrivateKey("classpath:ssl/pkcs8/key-rsa-encrypted.pem")
.withPrivateKey("classpath:pkcs8/key-rsa-encrypted.pem")
.withPrivateKeyPassword("test");
PemSslStoreDetails trustStoreDetails = null;
PemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);
@ -141,6 +144,7 @@ class PemSslStoreBundleTests {
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void createWithDetailsWhenHasKeyStoreDetailsAndTrustStoreDetailsWithoutKey() {
PemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate("classpath:test-cert.pem")
.withPrivateKey("classpath:test-key.pem");
@ -151,6 +155,7 @@ class PemSslStoreBundleTests {
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void createWithDetailsWhenHasKeyStoreDetailsAndTrustStoreDetails() {
PemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate("classpath:test-cert.pem")
.withPrivateKey("classpath:test-key.pem");
@ -173,6 +178,7 @@ class PemSslStoreBundleTests {
@Test
@SuppressWarnings("removal")
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void createWithDetailsWhenHasKeyStoreDetailsAndTrustStoreDetailsAndAlias() {
PemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate("classpath:test-cert.pem")
.withPrivateKey("classpath:test-key.pem");
@ -184,6 +190,7 @@ class PemSslStoreBundleTests {
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void createWithDetailsWhenHasStoreType() {
PemSslStoreDetails keyStoreDetails = new PemSslStoreDetails("PKCS12", "classpath:test-cert.pem",
"classpath:test-key.pem");
@ -195,6 +202,7 @@ class PemSslStoreBundleTests {
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void createWithDetailsWhenHasKeyStoreDetailsAndTrustStoreDetailsAndKeyPassword() {
PemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate("classpath:test-cert.pem")
.withPrivateKey("classpath:test-key.pem")

View File

@ -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.
@ -36,6 +36,7 @@ import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundleKey;
import org.springframework.boot.ssl.jks.JksSslStoreBundle;
import org.springframework.boot.ssl.jks.JksSslStoreDetails;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.Ssl;
@ -124,6 +125,7 @@ abstract class AbstractClientHttpRequestFactoriesTests<T extends ClientHttpReque
@ParameterizedTest
@ValueSource(strings = { "GET", "POST" })
@WithPackageResources("test.jks")
void connectWithSslBundle(String httpMethod) throws Exception {
TomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory(0);
Ssl ssl = new Ssl();

View File

@ -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.
@ -62,6 +62,8 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
import org.springframework.boot.testsupport.classpath.resources.ResourcePath;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.web.server.Compression;
import org.springframework.boot.web.server.GracefulShutdownResult;
@ -230,9 +232,10 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
}
@Test
void sslCiphersConfiguration() {
@WithPackageResources("test.jks")
void sslCiphersConfiguration(@ResourcePath("test.jks") String keyStore) {
Ssl ssl = new Ssl();
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStore(keyStore);
ssl.setKeyStorePassword("secret");
ssl.setKeyPassword("password");
ssl.setCiphers(new String[] { "ALPHA", "BRAVO", "CHARLIE" });
@ -261,9 +264,10 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
}
@Test
void sslEnabledMultiProtocolsConfiguration() {
@WithPackageResources("test.jks")
void sslEnabledMultiProtocolsConfiguration(@ResourcePath("test.jks") String keyStore) {
JettyServletWebServerFactory factory = getFactory();
factory.setSsl(getSslSettings("TLSv1.1", "TLSv1.2"));
factory.setSsl(getSslSettings(keyStore, "TLSv1.1", "TLSv1.2"));
this.webServer = factory.getWebServer();
this.webServer.start();
JettyWebServer jettyWebServer = (JettyWebServer) this.webServer;
@ -274,9 +278,10 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
}
@Test
void sslEnabledProtocolsConfiguration() {
@WithPackageResources("test.jks")
void sslEnabledProtocolsConfiguration(@ResourcePath("test.jks") String keyStore) {
JettyServletWebServerFactory factory = getFactory();
factory.setSsl(getSslSettings("TLSv1.1"));
factory.setSsl(getSslSettings(keyStore, "TLSv1.1"));
this.webServer = factory.getWebServer();
this.webServer.start();
JettyWebServer jettyWebServer = (JettyWebServer) this.webServer;
@ -393,9 +398,9 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
assertThat(((HttpResponse) requestResult).getFirstHeader("Connection").getValue()).isEqualTo("close");
}
private Ssl getSslSettings(String... enabledProtocols) {
private Ssl getSslSettings(String keyStore, String... enabledProtocols) {
Ssl ssl = new Ssl();
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStore(keyStore);
ssl.setKeyStorePassword("secret");
ssl.setKeyPassword("password");
ssl.setCiphers(new String[] { "ALPHA", "BRAVO", "CHARLIE" });
@ -426,6 +431,7 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
}
@Test
@WithPackageResources("test.jks")
void basicSslClasspathKeyStore() throws Exception {
testBasicSslWithKeyStore("classpath:test.jks");
}
@ -479,12 +485,13 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
}
@Test
@WithPackageResources("test.jks")
void specificIPAddressWithSslIsNotReverseResolved() throws Exception {
JettyServletWebServerFactory factory = getFactory();
InetAddress localhost = InetAddress.getLocalHost();
factory.setAddress(InetAddress.getByAddress(localhost.getAddress()));
Ssl ssl = new Ssl();
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStore("classpath:test.jks");
ssl.setKeyStorePassword("secret");
ssl.setKeyPassword("password");
factory.setSsl(ssl);

View File

@ -30,6 +30,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.OS;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.testsupport.junit.DisabledOnOs;
import org.springframework.boot.testsupport.ssl.MockPkcs11Security;
import org.springframework.boot.testsupport.ssl.MockPkcs11SecurityProvider;
@ -53,6 +54,7 @@ class SslServerCustomizerTests {
@Test
@SuppressWarnings("rawtypes")
@WithPackageResources("test.jks")
void whenHttp2IsNotEnabledServerConnectorHasSslAndHttpConnectionFactories() {
Server server = createCustomizedServer();
assertThat(server.getConnectors()).hasSize(1);
@ -63,6 +65,7 @@ class SslServerCustomizerTests {
@Test
@SuppressWarnings("rawtypes")
@WithPackageResources("test.jks")
@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = "aarch64",
disabledReason = "conscrypt doesn't support Linux/macOS aarch64, see https://github.com/google/conscrypt/issues/1051")
void whenHttp2IsEnabledServerConnectorsHasSslAlpnH2AndHttpConnectionFactories() {
@ -77,6 +80,7 @@ class SslServerCustomizerTests {
}
@Test
@WithPackageResources("test.jks")
@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = "aarch64",
disabledReason = "conscrypt doesn't support Linux/macOS aarch64, see https://github.com/google/conscrypt/issues/1051")
void alpnConnectionFactoryHasNullDefaultProtocolToAllowNegotiationToHttp11() {
@ -98,11 +102,12 @@ class SslServerCustomizerTests {
}
@Test
@WithPackageResources("test.jks")
void configureSslWhenSslIsEnabledWithPkcs11AndKeyStoreThrowsException() {
Ssl ssl = new Ssl();
ssl.setKeyStoreType("PKCS11");
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStore("classpath:test.jks");
ssl.setKeyPassword("password");
assertThatIllegalStateException().isThrownBy(() -> {
SslServerCustomizer customizer = new SslServerCustomizer(null, null, null, WebServerSslBundle.get(ssl));

View File

@ -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.
@ -39,6 +39,7 @@ import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.ssl.pem.PemSslStoreBundle;
import org.springframework.boot.ssl.pem.PemSslStoreDetails;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactoryTests;
import org.springframework.boot.web.server.PortInUseException;
@ -133,12 +134,14 @@ class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactor
}
@Test
@WithPackageResources("test.jks")
void whenSslIsConfiguredWithAValidAliasARequestSucceeds() {
Mono<String> result = testSslWithAlias("test-alias");
StepVerifier.create(result).expectNext("Hello World").expectComplete().verify(Duration.ofSeconds(30));
}
@Test
@WithPackageResources({ "1.key", "1.crt", "2.key", "2.crt" })
void whenSslBundleIsUpdatedThenSslIsReloaded() {
DefaultSslBundleRegistry bundles = new DefaultSslBundleRegistry("bundle1", createSslBundle("1.key", "1.crt"));
Mono<String> result = testSslWithBundle(bundles, "bundle1");
@ -231,9 +234,7 @@ class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactor
private static SslBundle createSslBundle(String key, String certificate) {
return SslBundle.of(new PemSslStoreBundle(
new PemSslStoreDetails(null, "classpath:org/springframework/boot/web/embedded/netty/" + certificate,
"classpath:org/springframework/boot/web/embedded/netty/" + key),
null));
new PemSslStoreDetails(null, "classpath:" + certificate, "classpath:" + key), null));
}
static class NoPortNettyReactiveWebServerFactory extends NettyReactiveWebServerFactory {

View File

@ -28,6 +28,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.testsupport.ssl.MockPkcs11Security;
import org.springframework.boot.testsupport.ssl.MockPkcs11SecurityProvider;
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
@ -71,6 +72,7 @@ class SslConnectorCustomizerTests {
}
@Test
@WithPackageResources("test.jks")
void sslCiphersConfiguration() throws Exception {
Ssl ssl = new Ssl();
ssl.setKeyStore("classpath:test.jks");
@ -85,10 +87,11 @@ class SslConnectorCustomizerTests {
}
@Test
@WithPackageResources("test.jks")
void sslEnabledMultipleProtocolsConfiguration() throws Exception {
Ssl ssl = new Ssl();
ssl.setKeyPassword("password");
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStore("classpath:test.jks");
ssl.setEnabledProtocols(new String[] { "TLSv1.1", "TLSv1.2" });
ssl.setCiphers(new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "BRAVO" });
Connector connector = this.tomcat.getConnector();
@ -101,10 +104,11 @@ class SslConnectorCustomizerTests {
}
@Test
@WithPackageResources("test.jks")
void sslEnabledProtocolsConfiguration() throws Exception {
Ssl ssl = new Ssl();
ssl.setKeyPassword("password");
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStore("classpath:test.jks");
ssl.setEnabledProtocols(new String[] { "TLSv1.2" });
ssl.setCiphers(new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "BRAVO" });
Connector connector = this.tomcat.getConnector();
@ -126,11 +130,12 @@ class SslConnectorCustomizerTests {
}
@Test
@WithPackageResources("test.jks")
void customizeWhenSslIsEnabledWithPkcs11AndKeyStoreThrowsException() {
Ssl ssl = new Ssl();
ssl.setKeyStoreType("PKCS11");
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStore("classpath:test.jks");
ssl.setKeyPassword("password");
assertThatIllegalStateException().isThrownBy(() -> {
SslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, this.tomcat.getConnector(),

View File

@ -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.
@ -80,6 +80,7 @@ import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
import org.springframework.boot.ssl.DefaultSslBundleRegistry;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.web.server.PortInUseException;
import org.springframework.boot.web.server.Shutdown;
@ -683,11 +684,12 @@ class TomcatServletWebServerFactoryTests extends AbstractServletWebServerFactory
}
@Test
@WithPackageResources("test.jks")
void sslWithHttp11Nio2Protocol() throws Exception {
TomcatServletWebServerFactory factory = getFactory();
addTestTxtFile(factory);
factory.setProtocol(Http11Nio2Protocol.class.getName());
factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks"));
factory.setSsl(getSsl(null, "password", "classpath:test.jks"));
this.webServer = factory.getWebServer();
this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(

View File

@ -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.
@ -38,7 +38,9 @@ import io.undertow.servlet.api.ServletContainer;
import jakarta.servlet.ServletRegistration.Dynamic;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.apache.jasper.servlet.JspServlet;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.AfterEach;
@ -46,6 +48,7 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.testsupport.web.servlet.ExampleServlet;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.GracefulShutdownResult;
@ -55,6 +58,7 @@ import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory;
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactoryTests;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -155,7 +159,7 @@ class UndertowServletWebServerFactoryTests extends AbstractServletWebServerFacto
@Test
void basicSslClasspathKeyStore() throws Exception {
testBasicSslWithKeyStore("classpath:test.jks");
testBasicSslWithKeyStore("classpath:org/springframework/boot/web/server/test.jks");
}
@Test
@ -286,6 +290,7 @@ class UndertowServletWebServerFactoryTests extends AbstractServletWebServerFacto
}
@Test
@WithPackageResources("restricted.jks")
void sslRestrictedProtocolsEmptyCipherFailure() {
assertThatIOException()
.isThrownBy(() -> testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.2" },
@ -294,6 +299,7 @@ class UndertowServletWebServerFactoryTests extends AbstractServletWebServerFacto
}
@Test
@WithPackageResources("restricted.jks")
void sslRestrictedProtocolsECDHETLS1Failure() {
assertThatIOException()
.isThrownBy(() -> testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1" },
@ -302,18 +308,21 @@ class UndertowServletWebServerFactoryTests extends AbstractServletWebServerFacto
}
@Test
@WithPackageResources("restricted.jks")
void sslRestrictedProtocolsECDHESuccess() throws Exception {
testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.2" },
new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" });
}
@Test
@WithPackageResources("restricted.jks")
void sslRestrictedProtocolsRSATLS12Success() throws Exception {
testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.2" },
new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA256" });
}
@Test
@WithPackageResources("restricted.jks")
void sslRestrictedProtocolsRSATLS11Failure() {
assertThatIOException()
.isThrownBy(() -> testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.1" },
@ -374,4 +383,15 @@ class UndertowServletWebServerFactoryTests extends AbstractServletWebServerFacto
return ((UndertowServletWebServer) this.webServer).getStartLogMessage();
}
private void testRestrictedSSLProtocolsAndCipherSuites(String[] protocols, String[] ciphers) throws Exception {
AbstractServletWebServerFactory factory = getFactory();
factory.setSsl(getSsl(null, "password", "classpath:restricted.jks", null, protocols, ciphers));
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build());
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory);
assertThat(getResponse(getLocalUrl("https", "/hello"), requestFactory)).contains("scheme=https");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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.
@ -21,6 +21,7 @@ import java.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.support.GenericApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
@ -32,8 +33,6 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class MustacheViewResolverTests {
private final String prefix = "classpath:/" + getClass().getPackage().getName().replace(".", "/") + "/";
private final MustacheViewResolver resolver = new MustacheViewResolver();
@BeforeEach
@ -41,7 +40,7 @@ class MustacheViewResolverTests {
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.refresh();
this.resolver.setApplicationContext(applicationContext);
this.resolver.setPrefix(this.prefix);
this.resolver.setPrefix("classpath:");
this.resolver.setSuffix(".html");
}
@ -51,6 +50,7 @@ class MustacheViewResolverTests {
}
@Test
@WithResource(name = "template.html", content = "Hello {{World}}")
void resolveExisting() {
assertThat(this.resolver.resolveViewName("template", null).block(Duration.ofSeconds(30))).isNotNull();
}

View File

@ -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.
@ -24,6 +24,7 @@ import com.samskivert.mustache.Mustache;
import org.junit.jupiter.api.Test;
import reactor.test.StepVerifier;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
@ -38,17 +39,15 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class MustacheViewTests {
private final String templateUrl = "classpath:/" + getClass().getPackage().getName().replace(".", "/")
+ "/template.html";
private final StaticApplicationContext context = new StaticApplicationContext();
@Test
@WithResource(name = "template.html", content = "Hello {{World}}")
void viewResolvesHandlebars() {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test").build());
MustacheView view = new MustacheView();
view.setCompiler(Mustache.compiler());
view.setUrl(this.templateUrl);
view.setUrl("classpath:template.html");
view.setCharset(StandardCharsets.UTF_8.displayName());
view.setApplicationContext(this.context);
view.render(Collections.singletonMap("World", "Spring"), MediaType.TEXT_HTML, exchange)

View File

@ -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.web.reactive.server;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
@ -54,12 +53,15 @@ import reactor.netty.http.Http11SslContextSpec;
import reactor.netty.http.client.HttpClient;
import reactor.test.StepVerifier;
import org.springframework.boot.testsupport.classpath.resources.ResourcePath;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.web.server.Compression;
import org.springframework.boot.web.server.GracefulShutdownResult;
import org.springframework.boot.web.server.Http2;
import org.springframework.boot.web.server.Shutdown;
import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.server.WebServer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
@ -165,13 +167,15 @@ public abstract class AbstractReactiveWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void basicSslFromClassPath() {
testBasicSslWithKeyStore("classpath:test.jks", "password");
}
@Test
void basicSslFromFileSystem() {
testBasicSslWithKeyStore("src/test/resources/test.jks", "password");
@WithPackageResources("test.jks")
void basicSslFromFileSystem(@ResourcePath("test.jks") String keyStore) {
testBasicSslWithKeyStore(keyStore, "password");
}
@ -199,6 +203,7 @@ public abstract class AbstractReactiveWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslWithValidAlias() {
String keyStore = "classpath:test.jks";
String keyPassword = "password";
@ -228,6 +233,7 @@ public abstract class AbstractReactiveWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslWithInvalidAliasFailsDuringStartup() {
String keyStore = "classpath:test.jks";
String keyPassword = "password";
@ -254,6 +260,7 @@ public abstract class AbstractReactiveWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslWantsClientAuthenticationSucceedsWithClientCertificate() throws Exception {
Ssl ssl = new Ssl();
ssl.setClientAuth(Ssl.ClientAuth.WANT);
@ -265,6 +272,7 @@ public abstract class AbstractReactiveWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslWantsClientAuthenticationSucceedsWithoutClientCertificate() {
Ssl ssl = new Ssl();
ssl.setClientAuth(Ssl.ClientAuth.WANT);
@ -275,10 +283,10 @@ public abstract class AbstractReactiveWebServerFactoryTests {
testClientAuthSuccess(ssl, buildTrustAllSslConnector());
}
protected ReactorClientHttpConnector buildTrustAllSslWithClientKeyConnector(String keyStoreFile,
protected ReactorClientHttpConnector buildTrustAllSslWithClientKeyConnector(String keyStore,
String keyStorePassword) throws Exception {
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream stream = new FileInputStream("src/test/resources/" + keyStoreFile)) {
try (InputStream stream = new ClassPathResource(keyStore).getInputStream()) {
clientKeyStore.load(stream, "secret".toCharArray());
}
KeyManagerFactory clientKeyManagerFactory = KeyManagerFactory
@ -312,6 +320,7 @@ public abstract class AbstractReactiveWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslNeedsClientAuthenticationSucceedsWithClientCertificate() throws Exception {
Ssl ssl = new Ssl();
ssl.setClientAuth(Ssl.ClientAuth.NEED);
@ -323,6 +332,7 @@ public abstract class AbstractReactiveWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslNeedsClientAuthenticationFailsWithoutClientCertificate() {
Ssl ssl = new Ssl();
ssl.setClientAuth(Ssl.ClientAuth.NEED);
@ -334,6 +344,7 @@ public abstract class AbstractReactiveWebServerFactoryTests {
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem", "test.p12" })
void sslWithPemCertificates() throws Exception {
Ssl ssl = new Ssl();
ssl.setClientAuth(Ssl.ClientAuth.NEED);

View File

@ -22,6 +22,8 @@ import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundleKey;
import org.springframework.boot.ssl.SslOptions;
import org.springframework.boot.ssl.SslStoreBundle;
import org.springframework.boot.testsupport.classpath.resources.ResourcePath;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.testsupport.ssl.MockPkcs11Security;
import org.springframework.boot.testsupport.ssl.MockPkcs11SecurityProvider;
@ -47,6 +49,7 @@ class WebServerSslBundleTests {
}
@Test
@WithPackageResources("test.p12")
void whenFromJksProperties() {
Ssl ssl = new Ssl();
ssl.setKeyStore("classpath:test.p12");
@ -77,11 +80,12 @@ class WebServerSslBundleTests {
}
@Test
void whenFromJksPropertiesWithPkcs11StoreType() {
@WithPackageResources("test.jks")
void whenFromJksPropertiesWithPkcs11StoreType(@ResourcePath("test.jks") String keyStorePath) {
Ssl ssl = new Ssl();
ssl.setKeyStoreType("PKCS11");
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStore(keyStorePath);
ssl.setKeyPassword("password");
ssl.setClientAuth(Ssl.ClientAuth.NONE);
assertThatIllegalStateException().isThrownBy(() -> WebServerSslBundle.get(ssl))
@ -108,6 +112,7 @@ class WebServerSslBundleTests {
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem", "test-cert-chain.pem" })
void whenFromPemProperties() {
Ssl ssl = new Ssl();
ssl.setCertificate("classpath:test-cert.pem");
@ -135,6 +140,7 @@ class WebServerSslBundleTests {
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem", "test.p12" })
void whenPemKeyStoreAndJksTrustStoreProperties() {
Ssl ssl = new Ssl();
ssl.setCertificate("classpath:test-cert.pem");
@ -163,6 +169,7 @@ class WebServerSslBundleTests {
}
@Test
@WithPackageResources({ "test.p12", "test-cert-chain.pem" })
void whenJksKeyStoreAndPemTrustStoreProperties() {
Ssl ssl = new Ssl();
ssl.setKeyStore("classpath:test.p12");

View File

@ -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.
@ -21,6 +21,7 @@ import java.net.URI;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
@ -86,6 +87,7 @@ class ServletWebServerMvcIntegrationTests {
}
@Test
@WithResource(name = "conf.properties", content = "context=/example")
void advancedConfig() throws Exception {
this.context = new AnnotationConfigServletWebServerApplicationContext(AdvancedConfig.class);
doTest(this.context, "/example/spring/hello");
@ -161,7 +163,7 @@ class ServletWebServerMvcIntegrationTests {
@Configuration(proxyBeanMethods = false)
@EnableWebMvc
@PropertySource("classpath:/org/springframework/boot/web/servlet/context/conf.properties")
@PropertySource("classpath:conf.properties")
static class AdvancedConfig {
private final Environment env;

View File

@ -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.
@ -121,6 +121,8 @@ import org.springframework.boot.ssl.pem.PemSslStoreBundle;
import org.springframework.boot.ssl.pem.PemSslStoreDetails;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.boot.system.ApplicationTemp;
import org.springframework.boot.testsupport.classpath.resources.ResourcePath;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
@ -426,16 +428,19 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void basicSslFromClassPath() throws Exception {
testBasicSslWithKeyStore("classpath:test.jks");
}
@Test
void basicSslFromFileSystem() throws Exception {
testBasicSslWithKeyStore("src/test/resources/test.jks");
@WithPackageResources("test.jks")
void basicSslFromFileSystem(@ResourcePath("test.jks") String keyStore) throws Exception {
testBasicSslWithKeyStore(keyStore);
}
@Test
@WithPackageResources("test.jks")
void sslDisabled() throws Exception {
AbstractServletWebServerFactory factory = getFactory();
Ssl ssl = getSsl(null, "password", "classpath:test.jks");
@ -451,9 +456,10 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslGetScheme() throws Exception { // gh-2232
AbstractServletWebServerFactory factory = getFactory();
factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks"));
factory.setSsl(getSsl(null, "password", "classpath:test.jks"));
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
@ -463,9 +469,10 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslKeyAlias() throws Exception {
AbstractServletWebServerFactory factory = getFactory();
Ssl ssl = getSsl(null, "password", "test-alias", "src/test/resources/test.jks");
Ssl ssl = getSsl(null, "password", "test-alias", "classpath:test.jks");
factory.setSsl(ssl);
ServletRegistrationBean<ExampleServlet> registration = new ServletRegistrationBean<>(
new ExampleServlet(true, false), "/hello");
@ -483,9 +490,10 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslWithInvalidAliasFailsDuringStartup() {
AbstractServletWebServerFactory factory = getFactory();
Ssl ssl = getSsl(null, "password", "test-alias-404", "src/test/resources/test.jks");
Ssl ssl = getSsl(null, "password", "test-alias-404", "classpath:test.jks");
factory.setSsl(ssl);
ServletRegistrationBean<ExampleServlet> registration = new ServletRegistrationBean<>(
new ExampleServlet(true, false), "/hello");
@ -499,9 +507,10 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void serverHeaderIsDisabledByDefaultWhenUsingSsl() throws Exception {
AbstractServletWebServerFactory factory = getFactory();
factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks"));
factory.setSsl(getSsl(null, "password", "classpath:test.jks"));
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
@ -516,10 +525,11 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void serverHeaderCanBeCustomizedWhenUsingSsl() throws Exception {
AbstractServletWebServerFactory factory = getFactory();
factory.setServerHeader("MyServer");
factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks"));
factory.setSsl(getSsl(null, "password", "classpath:test.jks"));
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
@ -546,14 +556,15 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
void pkcs12KeyStoreAndTrustStore() throws Exception {
@WithPackageResources("test.p12")
void pkcs12KeyStoreAndTrustStore(@ResourcePath("test.p12") File keyStoreFile) throws Exception {
AbstractServletWebServerFactory factory = getFactory();
addTestTxtFile(factory);
factory.setSsl(getSsl(ClientAuth.NEED, null, "classpath:test.p12", "classpath:test.p12", null, null));
this.webServer = factory.getWebServer();
this.webServer.start();
KeyStore keyStore = KeyStore.getInstance("pkcs12");
loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12"));
loadStore(keyStore, new FileSystemResource(keyStoreFile));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, "secret".toCharArray())
@ -563,14 +574,15 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
void pemKeyStoreAndTrustStore() throws Exception {
@WithPackageResources({ "test.p12", "test-cert.pem", "test-key.pem" })
void pemKeyStoreAndTrustStore(@ResourcePath("test.p12") File keyStoreFile) throws Exception {
AbstractServletWebServerFactory factory = getFactory();
addTestTxtFile(factory);
factory.setSsl(getSsl("classpath:test-cert.pem", "classpath:test-key.pem"));
this.webServer = factory.getWebServer();
this.webServer.start();
KeyStore keyStore = KeyStore.getInstance("pkcs12");
loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12"));
loadStore(keyStore, new FileSystemResource(keyStoreFile));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, "secret".toCharArray())
@ -580,7 +592,8 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
void pkcs12KeyStoreAndTrustStoreFromBundle() throws Exception {
@WithPackageResources("test.p12")
void pkcs12KeyStoreAndTrustStoreFromBundle(@ResourcePath("test.p12") File keyStoreFile) throws Exception {
AbstractServletWebServerFactory factory = getFactory();
addTestTxtFile(factory);
factory.setSsl(Ssl.forBundle("test"));
@ -589,7 +602,7 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer = factory.getWebServer();
this.webServer.start();
KeyStore keyStore = KeyStore.getInstance("pkcs12");
loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12"));
loadStore(keyStore, new FileSystemResource(keyStoreFile));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, "secret".toCharArray())
@ -599,7 +612,8 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
void pemKeyStoreAndTrustStoreFromBundle() throws Exception {
@WithPackageResources({ "test.p12", "test-cert.pem", "test-key.pem" })
void pemKeyStoreAndTrustStoreFromBundle(@ResourcePath("test.p12") File keyStoreFile) throws Exception {
AbstractServletWebServerFactory factory = getFactory();
addTestTxtFile(factory);
factory.setSsl(Ssl.forBundle("test"));
@ -608,7 +622,7 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer = factory.getWebServer();
this.webServer.start();
KeyStore keyStore = KeyStore.getInstance("pkcs12");
loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12"));
loadStore(keyStore, new FileSystemResource(keyStoreFile));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, "secret".toCharArray())
@ -618,7 +632,9 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
void sslNeedsClientAuthenticationSucceedsWithClientCertificate() throws Exception {
@WithPackageResources("test.jks")
void sslNeedsClientAuthenticationSucceedsWithClientCertificate(@ResourcePath("test.jks") File keyStoreFile)
throws Exception {
AbstractServletWebServerFactory factory = getFactory();
factory.setRegisterDefaultServlet(true);
addTestTxtFile(factory);
@ -626,7 +642,7 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer = factory.getWebServer();
this.webServer.start();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
loadStore(keyStore, new FileSystemResource("src/test/resources/test.jks"));
loadStore(keyStore, new FileSystemResource(keyStoreFile));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, "password".toCharArray())
@ -636,6 +652,7 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslNeedsClientAuthenticationFailsWithoutClientCertificate() throws Exception {
AbstractServletWebServerFactory factory = getFactory();
addTestTxtFile(factory);
@ -650,7 +667,9 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
void sslWantsClientAuthenticationSucceedsWithClientCertificate() throws Exception {
@WithPackageResources("test.jks")
void sslWantsClientAuthenticationSucceedsWithClientCertificate(@ResourcePath("test.jks") File keyStoreFile)
throws Exception {
AbstractServletWebServerFactory factory = getFactory();
addTestTxtFile(factory);
factory
@ -658,7 +677,7 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer = factory.getWebServer();
this.webServer.start();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
loadStore(keyStore, new FileSystemResource("src/test/resources/test.jks"));
loadStore(keyStore, new FileSystemResource(keyStoreFile));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, "password".toCharArray())
@ -668,6 +687,7 @@ public abstract class AbstractServletWebServerFactoryTests {
}
@Test
@WithPackageResources("test.jks")
void sslWantsClientAuthenticationSucceedsWithoutClientCertificate() throws Exception {
AbstractServletWebServerFactory factory = getFactory();
addTestTxtFile(factory);
@ -706,7 +726,7 @@ public abstract class AbstractServletWebServerFactoryTests {
return getSsl(clientAuth, keyPassword, keyAlias, keyStore, null, null, null);
}
private Ssl getSsl(ClientAuth clientAuth, String keyPassword, String keyStore, String trustStore,
protected Ssl getSsl(ClientAuth clientAuth, String keyPassword, String keyStore, String trustStore,
String[] supportedProtocols, String[] ciphers) {
return getSsl(clientAuth, keyPassword, null, keyStore, trustStore, supportedProtocols, ciphers);
}
@ -767,17 +787,6 @@ public abstract class AbstractServletWebServerFactoryTests {
return SslBundle.of(stores);
}
protected void testRestrictedSSLProtocolsAndCipherSuites(String[] protocols, String[] ciphers) throws Exception {
AbstractServletWebServerFactory factory = getFactory();
factory.setSsl(getSsl(null, "password", "src/test/resources/restricted.jks", null, protocols, ciphers));
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build());
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory);
assertThat(getResponse(getLocalUrl("https", "/hello"), requestFactory)).contains("scheme=https");
}
protected HttpComponentsClientHttpRequestFactory createHttpComponentsRequestFactory(
SSLConnectionSocketFactory socketFactory) {
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
@ -949,7 +958,7 @@ public abstract class AbstractServletWebServerFactoryTests {
AbstractServletWebServerFactory factory = getFactory();
Ssl ssl = new Ssl();
ssl.setEnabled(true);
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStore("src/test/resources/org/springframework/boot/web/server/test.jks");
ssl.setKeyPassword("password");
factory.setSsl(ssl);
factory.getSession().setTrackingModes(EnumSet.of(SessionTrackingMode.SSL));

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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.
@ -19,6 +19,7 @@ package org.springframework.boot.web.servlet.view;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.servlet.View;
@ -33,8 +34,6 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class MustacheViewResolverTests {
private final String prefix = "classpath:/" + getClass().getPackage().getName().replace(".", "/") + "/";
private final MustacheViewResolver resolver = new MustacheViewResolver();
@BeforeEach
@ -43,7 +42,7 @@ class MustacheViewResolverTests {
applicationContext.refresh();
this.resolver.setApplicationContext(applicationContext);
this.resolver.setServletContext(new MockServletContext());
this.resolver.setPrefix(this.prefix);
this.resolver.setPrefix("classpath:");
this.resolver.setSuffix(".html");
}
@ -53,11 +52,13 @@ class MustacheViewResolverTests {
}
@Test
@WithResource(name = "template.html", content = "Hello {{World}}")
void resolveExisting() throws Exception {
assertThat(this.resolver.resolveViewName("template", null)).isNotNull();
}
@Test
@WithResource(name = "template.html", content = "Hello {{World}}")
void setsContentType() throws Exception {
this.resolver.setContentType("application/octet-stream");
View view = this.resolver.resolveViewName("template", null);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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 com.samskivert.mustache.Mustache;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@ -37,9 +38,6 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class MustacheViewTests {
private final String templateUrl = "classpath:/" + getClass().getPackage().getName().replace(".", "/")
+ "/template.html";
private final MockHttpServletRequest request = new MockHttpServletRequest();
private final MockHttpServletResponse response = new MockHttpServletResponse();
@ -55,10 +53,11 @@ class MustacheViewTests {
}
@Test
@WithResource(name = "template.html", content = "Hello {{World}}")
void viewResolvesHandlebars() throws Exception {
MustacheView view = new MustacheView();
view.setCompiler(Mustache.compiler());
view.setUrl(this.templateUrl);
view.setUrl("classpath:template.html");
view.setApplicationContext(this.context);
view.render(Collections.singletonMap("World", "Spring"), this.request, this.response);
assertThat(this.response.getContentAsString().trim()).isEqualTo("Hello Spring");

View File

@ -1,13 +0,0 @@
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.context.config.TestPropertySourceLoader1,\
org.springframework.boot.context.config.TestPropertySourceLoader2
org.springframework.boot.context.config.ConfigDataLocationResolver=\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests.LocationResolver,\
org.springframework.boot.context.config.TestConfigDataBootstrap.LocationResolver,\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.LocationResolver
org.springframework.boot.context.config.ConfigDataLoader=\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests.Loader,\
org.springframework.boot.context.config.TestConfigDataBootstrap.Loader,\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.Loader

View File

@ -1,6 +0,0 @@
# A comment spanning a complete line
class1
class2 # with comment at the end
# Comment with some whitespace in front
class3

View File

@ -1 +0,0 @@
spring.output.ansi.enabled=never

View File

@ -1,4 +0,0 @@
test1=test1
#---
spring.config.activate.on-profile=other
test2=test2

View File

@ -1,6 +0,0 @@
spring.config.import=testbootstrap:test
spring.profiles.active=test
myprop=igotbound
#---
spring.config.activate.on-profile=test
myprofileprop=igotprofilebound

View File

@ -1 +0,0 @@
my.property=fromdevpropertiesfile

View File

@ -1,3 +0,0 @@
my.import=application-import-with-placeholder-imported
#---
spring.config.import=classpath:${my.import}.properties

View File

@ -1 +0,0 @@
my.value=application-import-with-placeholder-in-earlier-document-imported

View File

@ -1,6 +0,0 @@
my.import=application-import-with-placeholder-in-earlier-document-imported
#---
my.value=should-be-ignored
spring.config.activate.on-profile=missing
#---
spring.config.import=classpath:${my.import}.properties

View File

@ -1 +0,0 @@
my.value=application-import-with-placeholder-in-earlier-profile-document-imported

View File

@ -1,6 +0,0 @@
my.value=application-import-with-placeholder-in-earlier-profile-document
#---
my.import=application-import-with-placeholder-in-earlier-profile-document-imported
spring.config.activate.on-profile=missing
#---
spring.config.import=classpath:${my.import}.properties

View File

@ -1,6 +0,0 @@
my.import=application-import-with-placeholder-imported
#---
spring.config.import=classpath:${my.import}.properties
#---
my.import=badbadbad
spring.config.activate.on-profile=missing

View File

@ -1,2 +0,0 @@
my.import=application-import-with-placeholder-imported
spring.config.import=classpath:${my.import}.properties

View File

@ -1,2 +0,0 @@
spring.config.import=classpath:application-import-with-profile-variant-imported-dev.properties
my.value=application-import-with-profile-variant-and-direct-profile-import-dev

View File

@ -1,2 +0,0 @@
spring.config.import=classpath:application-import-with-profile-variant-imported.properties
my.value=application-import-with-profile-variant-and-direct-profile-import

View File

@ -1 +0,0 @@
my.value=application-import-with-profile-variant-dev

View File

@ -1 +0,0 @@
my.value=application-import-with-profile-variant-imported-dev

View File

@ -1 +0,0 @@
my.value=application-import-with-profile-variant-imported

View File

@ -1,2 +0,0 @@
spring.config.import=classpath:application-import-with-profile-variant-imported.properties
my.value=application-import-with-profile-variant

View File

@ -1,6 +0,0 @@
spring.profiles.active=p1
spring.profiles.include=p2
#---
spring.config.activate.on-profile=p2
spring.profiles.include=p3

View File

@ -1,9 +0,0 @@
spring.profiles.active=p1
spring.profiles.include=p2
#---
myprofile=p4
spring.profiles.include=p3,${myprofile}
#---
myotherprofile=p5
spring.profiles.include=${myotherprofile}

View File

@ -1,7 +0,0 @@
spring.profiles.active=p1
spring.profiles.include=p2
#---
spring.profiles.include=p3,p4
#---
spring.profiles.include=p5

View File

@ -1 +0,0 @@
spring.profiles.include=specific

View File

@ -1 +0,0 @@
my.property=fromotherpropertiesfile

View File

@ -1 +0,0 @@
application-profile-specific-import-with-import-import-p1=true

View File

@ -1 +0,0 @@
application-profile-specific-import-with-import-import-p2=true

View File

@ -1 +0,0 @@
application-profile-specific-import-with-import-import=true

View File

@ -1,2 +0,0 @@
application-profile-specific-import-with-import-p1=true
spring.config.import=application-profile-specific-import-with-import-import.properties

View File

@ -1,2 +0,0 @@
spring.profiles.active=p1,p2
application-profile-specific-import-with-import=true

View File

@ -1 +0,0 @@
spring.main.web-application-type: reactive

View File

@ -1,6 +0,0 @@
foo: bucket
value: 1234
my.property: fromapplicationproperties
sample.app.test.prop: *
my.placeholder: ${my.fallback}
duplicate=properties

Some files were not shown because too many files have changed in this diff Show More