Skip to content

Commit

Permalink
Add YamlPropertySourceFactory that can be used for loading YAML files…
Browse files Browse the repository at this point in the history
… through the @TestPropertySource annotation.
  • Loading branch information
nosan committed Oct 14, 2024
1 parent 2728344 commit b297962
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 1 deletion.
2 changes: 1 addition & 1 deletion spring-boot-project/spring-boot-test/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,5 @@ dependencies {
testImplementation("org.testng:testng")

testRuntimeOnly("org.junit.vintage:junit-vintage-engine")
testRuntimeOnly("org.yaml:snakeyaml")
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2012-2024 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.test.context;

import java.io.IOException;
import java.util.List;

import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.springframework.util.StringUtils;

/**
* An implementation of {@link PropertySourceFactory} that delegates the loading of
* {@code PropertySource} to {@link YamlPropertySourceLoader}. If the provided YAML file
* contains multiple documents (separated by {@code ---}), the property sources from later
* documents will take precedence, overriding any conflicting values defined in earlier
* documents.
*
* @author Dmytro Nosan
* @since 3.4.0
*/
public class YamlPropertySourceFactory implements PropertySourceFactory {

private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

@Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
Resource resource = encodedResource.getResource();
String propertySourceName = getPropertySourceName(name, resource);
List<PropertySource<?>> propertySources = this.loader.load(propertySourceName, resource);
return new YamlCompositePropertySource(propertySourceName, propertySources);
}

private static String getPropertySourceName(String name, Resource resource) {
if (StringUtils.hasText(name)) {
return name;
}
String description = resource.getDescription();
if (StringUtils.hasText(description)) {
return description;
}
return resource.getClass().getSimpleName() + "@" + System.identityHashCode(resource);
}

private static final class YamlCompositePropertySource extends CompositePropertySource {

YamlCompositePropertySource(String name, List<PropertySource<?>> propertySources) {
super(name);
propertySources.forEach(this::addFirstPropertySource);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2012-2024 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.test.context;

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Integration tests for {@link YamlPropertySourceFactory} with
* {@link TestPropertySource}.
*
* @author Dmytro Nosan
*/
@SpringJUnitConfig
@TestPropertySource(locations = { "classpath:test.yaml", "classpath:test1.yaml" },
factory = YamlPropertySourceFactory.class)
class YamlPropertySourceFactoryIntegrationTests {

@Autowired
private Environment environment;

@Test
void loadProperties() {
assertThat(this.environment.getProperty("spring.bar")).isEqualTo("bar");
assertThat(this.environment.getProperty("spring.foo")).isEqualTo("baz");
assertThat(this.environment.getProperty("spring.buzz")).isEqualTo("fazz");
}

@Configuration(proxyBeanMethods = false)
static class Config {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2012-2024 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.test.context;

import java.io.IOException;

import org.junit.jupiter.api.Test;

import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.EncodedResource;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.spy;

/**
* Tests for {@link YamlPropertySourceFactory}.
*
* @author Dmytro Nosan
*/
class YamlPropertySourceFactoryTests {

private final YamlPropertySourceFactory factory = new YamlPropertySourceFactory();

@Test
void shouldCreatePropertySourceWithYamlPropertySourceLoaderWithGivenName() throws IOException {
EncodedResource resource = new EncodedResource(new ClassPathResource("test.yaml"));
PropertySource<?> propertySource = this.factory.createPropertySource("test", resource);
assertThat(propertySource.getName()).isEqualTo("test");
assertProperties(propertySource);
}

@Test
void shouldCreatePropertySourceWithYamlPropertySourceLoaderWithResourceDescriptionName() throws IOException {
EncodedResource resource = new EncodedResource(new ClassPathResource("test.yaml"));
PropertySource<?> propertySource = this.factory.createPropertySource(null, resource);
assertThat(propertySource.getName()).isEqualTo("class path resource [test.yaml]");
assertProperties(propertySource);
}

@Test
void shouldCreatePropertySourceWithYamlPropertySourceLoaderWithGeneratedName() throws IOException {
ClassPathResource resource = spy(new ClassPathResource("test.yaml"));
willReturn(null).given(resource).getDescription();
PropertySource<?> propertySource = this.factory.createPropertySource(null, new EncodedResource(resource));
assertThat(propertySource.getName()).startsWith("ClassPathResource@");
assertProperties(propertySource);
}

private static void assertProperties(PropertySource<?> propertySource) {
assertThat(propertySource.getProperty("spring.bar")).isEqualTo("bar");
assertThat(propertySource.getProperty("spring.foo")).isEqualTo("baz");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
spring:
bar: foo
---
spring:
bar: bar
foo: baz
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
spring:
buzz: fazz

0 comments on commit b297962

Please sign in to comment.