Skip to content

Commit cbeb1bd

Browse files
committed
Add YamlPropertySourceFactory that can be used for loading YAML files through the @TestPropertySource annotation.
1 parent 35361d1 commit cbeb1bd

File tree

6 files changed

+206
-1
lines changed

6 files changed

+206
-1
lines changed

spring-boot-project/spring-boot-test/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,5 @@ dependencies {
5959
testImplementation("org.testng:testng")
6060

6161
testRuntimeOnly("org.junit.vintage:junit-vintage-engine")
62+
testRuntimeOnly("org.yaml:snakeyaml")
6263
}
63-
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.test.context;
18+
19+
import java.io.IOException;
20+
import java.util.List;
21+
22+
import org.springframework.boot.env.YamlPropertySourceLoader;
23+
import org.springframework.core.env.CompositePropertySource;
24+
import org.springframework.core.env.PropertySource;
25+
import org.springframework.core.io.Resource;
26+
import org.springframework.core.io.support.EncodedResource;
27+
import org.springframework.core.io.support.PropertySourceFactory;
28+
import org.springframework.util.StringUtils;
29+
30+
/**
31+
* An implementation of {@link PropertySourceFactory} that delegates the loading of
32+
* {@code PropertySource} to {@link YamlPropertySourceLoader}. If the provided YAML file
33+
* contains multiple documents (separated by {@code ---}), the property sources from later
34+
* documents will take precedence, overriding any conflicting values defined in earlier
35+
* documents.
36+
*
37+
* @author Dmytro Nosan
38+
* @since 3.4.0
39+
*/
40+
public class YamlPropertySourceFactory implements PropertySourceFactory {
41+
42+
private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
43+
44+
@Override
45+
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
46+
Resource resource = encodedResource.getResource();
47+
String propertySourceName = getPropertySourceName(name, resource);
48+
List<PropertySource<?>> propertySources = this.loader.load(propertySourceName, resource);
49+
return new YamlCompositePropertySource(propertySourceName, propertySources);
50+
}
51+
52+
private static String getPropertySourceName(String name, Resource resource) {
53+
if (StringUtils.hasText(name)) {
54+
return name;
55+
}
56+
String description = resource.getDescription();
57+
if (StringUtils.hasText(description)) {
58+
return description;
59+
}
60+
return resource.getClass().getSimpleName() + "@" + System.identityHashCode(resource);
61+
}
62+
63+
private static final class YamlCompositePropertySource extends CompositePropertySource {
64+
65+
YamlCompositePropertySource(String name, List<PropertySource<?>> propertySources) {
66+
super(name);
67+
propertySources.forEach(this::addFirstPropertySource);
68+
}
69+
70+
}
71+
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.test.context;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.context.annotation.Configuration;
23+
import org.springframework.core.env.Environment;
24+
import org.springframework.test.context.TestPropertySource;
25+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
29+
/**
30+
* Integration tests for {@link YamlPropertySourceFactory} with
31+
* {@link TestPropertySource}.
32+
*
33+
* @author Dmytro Nosan
34+
*/
35+
@SpringJUnitConfig
36+
@TestPropertySource(locations = { "classpath:test.yaml", "classpath:test1.yaml" },
37+
factory = YamlPropertySourceFactory.class)
38+
class YamlPropertySourceFactoryIntegrationTests {
39+
40+
@Autowired
41+
private Environment environment;
42+
43+
@Test
44+
void loadProperties() {
45+
assertThat(this.environment.getProperty("spring.bar")).isEqualTo("bar");
46+
assertThat(this.environment.getProperty("spring.foo")).isEqualTo("baz");
47+
assertThat(this.environment.getProperty("spring.buzz")).isEqualTo("fazz");
48+
}
49+
50+
@Configuration(proxyBeanMethods = false)
51+
static class Config {
52+
53+
}
54+
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.test.context;
18+
19+
import java.io.IOException;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.core.env.PropertySource;
24+
import org.springframework.core.io.ClassPathResource;
25+
import org.springframework.core.io.support.EncodedResource;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
import static org.mockito.BDDMockito.willReturn;
29+
import static org.mockito.Mockito.spy;
30+
31+
/**
32+
* Tests for {@link YamlPropertySourceFactory}.
33+
*
34+
* @author Dmytro Nosan
35+
*/
36+
class YamlPropertySourceFactoryTests {
37+
38+
private final YamlPropertySourceFactory factory = new YamlPropertySourceFactory();
39+
40+
@Test
41+
void shouldCreatePropertySourceWithYamlPropertySourceLoaderWithGivenName() throws IOException {
42+
EncodedResource resource = new EncodedResource(new ClassPathResource("test.yaml"));
43+
PropertySource<?> propertySource = this.factory.createPropertySource("test", resource);
44+
assertThat(propertySource.getName()).isEqualTo("test");
45+
assertProperties(propertySource);
46+
}
47+
48+
@Test
49+
void shouldCreatePropertySourceWithYamlPropertySourceLoaderWithResourceDescriptionName() throws IOException {
50+
EncodedResource resource = new EncodedResource(new ClassPathResource("test.yaml"));
51+
PropertySource<?> propertySource = this.factory.createPropertySource(null, resource);
52+
assertThat(propertySource.getName()).isEqualTo("class path resource [test.yaml]");
53+
assertProperties(propertySource);
54+
}
55+
56+
@Test
57+
void shouldCreatePropertySourceWithYamlPropertySourceLoaderWithGeneratedName() throws IOException {
58+
ClassPathResource resource = spy(new ClassPathResource("test.yaml"));
59+
willReturn(null).given(resource).getDescription();
60+
PropertySource<?> propertySource = this.factory.createPropertySource(null, new EncodedResource(resource));
61+
assertThat(propertySource.getName()).startsWith("ClassPathResource@");
62+
assertProperties(propertySource);
63+
}
64+
65+
private static void assertProperties(PropertySource<?> propertySource) {
66+
assertThat(propertySource.getProperty("spring.bar")).isEqualTo("bar");
67+
assertThat(propertySource.getProperty("spring.foo")).isEqualTo("baz");
68+
}
69+
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
spring:
2+
bar: foo
3+
---
4+
spring:
5+
bar: bar
6+
foo: baz
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
spring:
2+
buzz: fazz

0 commit comments

Comments
 (0)