Rename volumemount -> configtree

Closes gh-22941
pull/22948/head
Phillip Webb 4 years ago
parent 5579f9d1c4
commit 310ef6e999

@ -675,7 +675,7 @@ Locations will be processed in the order that they are defined, with later impor
[TIP] [TIP]
==== ====
Spring Boot includes pluggable API that allows various different location addresses to be supported. Spring Boot includes pluggable API that allows various different location addresses to be supported.
By default you can import Java Properties, YAML and volume mounts. By default you can import Java Properties, YAML and "`<<boot-features-external-config-files-configtree, configuration trees>>`".
Third-party jars can offer support for additional technologies (there's no requirement for files to be local). Third-party jars can offer support for additional technologies (there's no requirement for files to be local).
For example, you can imagine config data being from external stores such as Consul, Apache ZooKeeper or Netflix Archaius. For example, you can imagine config data being from external stores such as Consul, Apache ZooKeeper or Netflix Archaius.
@ -685,8 +685,8 @@ If you want to support your own locations, see the `ConfigDataLocationResolver`
[[boot-features-external-config-files-voumemounts]] [[boot-features-external-config-files-configtree]]
==== Using Volume Mount Properties ==== Using Configuration Trees
When running applications on a cloud platform (such as Kubernetes) you often need to read config values that the platform supplies. When running applications on a cloud platform (such as Kubernetes) you often need to read config values that the platform supplies.
It's not uncommon to use environment variables for such purposes, but this can have drawbacks, especially if the value is supposed to be kept secret. It's not uncommon to use environment variables for such purposes, but this can have drawbacks, especially if the value is supposed to be kept secret.
@ -696,10 +696,10 @@ For example, Kubernetes can volume mount both https://kubernetes.io/docs/tasks/c
There are two common volume mount patterns that can be use: There are two common volume mount patterns that can be use:
. A single file contains a complete set of properties (usually written as YAML). . A single file contains a complete set of properties (usually written as YAML).
. Multiple files are written to a directory with the filename becoming the '`key`' and the contents becoming the '`value`'. . Multiple files are written to a directory tree, with the filename becoming the '`key`' and the contents becoming the '`value`'.
For the first case, you can import the YAML or Properties file directly using `spring.config.import` as described <<boot-features-external-config-files-importing,above>>. For the first case, you can import the YAML or Properties file directly using `spring.config.import` as described <<boot-features-external-config-files-importing,above>>.
For the second case, you need to use the `volumemount:` prefix so that Spring Boot knows it needs to expose all the files as properties. For the second case, you need to use the `configtree:` prefix so that Spring Boot knows it needs to expose all the files as properties.
As an example, let's imagine that Kubernetes has mounted the following volume: As an example, let's imagine that Kubernetes has mounted the following volume:
@ -718,12 +718,12 @@ To import these properties, you can add the following to your `application.prope
[source,properties,indent=0] [source,properties,indent=0]
---- ----
spring.config.import=volumemount:/etc/config spring.config.import=configtree:/etc/config
---- ----
You can then access or inject `myapp.username` and `myapp.password` properties from the `Environment` in the usual way. You can then access or inject `myapp.username` and `myapp.password` properties from the `Environment` in the usual way.
TIP: Volume mounted values can be bound to both string `String` and `byte[]` types depending on the contents expected. TIP: Configuration tree values can be bound to both string `String` and `byte[]` types depending on the contents expected.

@ -20,21 +20,21 @@ import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections; import java.util.Collections;
import org.springframework.boot.env.VolumeMountDirectoryPropertySource; import org.springframework.boot.env.ConfigTreePropertySource;
/** /**
* {@link ConfigDataLoader} for directory locations mounted as volumes. * {@link ConfigDataLoader} for config tree locations.
* *
* @author Madhura Bhave * @author Madhura Bhave
* @author Phillip Webb * @author Phillip Webb
*/ */
class VolumeMountConfigDataLoader implements ConfigDataLoader<VolumeMountConfigDataLocation> { class ConfigTreeConfigDataLoader implements ConfigDataLoader<ConfigTreeConfigDataLocation> {
@Override @Override
public ConfigData load(VolumeMountConfigDataLocation location) throws IOException { public ConfigData load(ConfigTreeConfigDataLocation location) throws IOException {
Path path = location.getPath(); Path path = location.getPath();
String name = "Volume mount config '" + path + "'"; String name = "Config tree '" + path + "'";
VolumeMountDirectoryPropertySource source = new VolumeMountDirectoryPropertySource(name, path); ConfigTreePropertySource source = new ConfigTreePropertySource(name, path);
return new ConfigData(Collections.singletonList(source)); return new ConfigData(Collections.singletonList(source));
} }

@ -20,19 +20,21 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Objects; import java.util.Objects;
import org.springframework.boot.env.ConfigTreePropertySource;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* {@link ConfigDataLocation} backed by a directory mounted as a volume. * {@link ConfigDataLocation} backed by a config tree directory.
* *
* @author Madhura Bhave * @author Madhura Bhave
* @author Phillip Webb * @author Phillip Webb
* @see ConfigTreePropertySource
*/ */
class VolumeMountConfigDataLocation extends ConfigDataLocation { class ConfigTreeConfigDataLocation extends ConfigDataLocation {
private final Path path; private final Path path;
VolumeMountConfigDataLocation(String path) { ConfigTreeConfigDataLocation(String path) {
Assert.notNull(path, "Path must not be null"); Assert.notNull(path, "Path must not be null");
this.path = Paths.get(path).toAbsolutePath(); this.path = Paths.get(path).toAbsolutePath();
} }
@ -49,7 +51,7 @@ class VolumeMountConfigDataLocation extends ConfigDataLocation {
if (obj == null || getClass() != obj.getClass()) { if (obj == null || getClass() != obj.getClass()) {
return false; return false;
} }
VolumeMountConfigDataLocation other = (VolumeMountConfigDataLocation) obj; ConfigTreeConfigDataLocation other = (ConfigTreeConfigDataLocation) obj;
return Objects.equals(this.path, other.path); return Objects.equals(this.path, other.path);
} }
@ -60,7 +62,7 @@ class VolumeMountConfigDataLocation extends ConfigDataLocation {
@Override @Override
public String toString() { public String toString() {
return "volume mount [" + this.path + "]"; return "config tree [" + this.path + "]";
} }
} }

@ -20,15 +20,14 @@ import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* {@link ConfigDataLocationResolver} for volume mounted locations such as Kubernetes * {@link ConfigDataLocationResolver} for config tree locations.
* ConfigMaps and Secrets.
* *
* @author Madhura Bhave * @author Madhura Bhave
* @author Phillip Webb * @author Phillip Webb
*/ */
class VolumeMountConfigDataLocationResolver implements ConfigDataLocationResolver<VolumeMountConfigDataLocation> { class ConfigTreeConfigDataLocationResolver implements ConfigDataLocationResolver<ConfigTreeConfigDataLocation> {
private static final String PREFIX = "volumemount:"; private static final String PREFIX = "configtree:";
@Override @Override
public boolean isResolvable(ConfigDataLocationResolverContext context, String location) { public boolean isResolvable(ConfigDataLocationResolverContext context, String location) {
@ -36,8 +35,8 @@ class VolumeMountConfigDataLocationResolver implements ConfigDataLocationResolve
} }
@Override @Override
public List<VolumeMountConfigDataLocation> resolve(ConfigDataLocationResolverContext context, String location) { public List<ConfigTreeConfigDataLocation> resolve(ConfigDataLocationResolverContext context, String location) {
VolumeMountConfigDataLocation resolved = new VolumeMountConfigDataLocation(location.substring(PREFIX.length())); ConfigTreeConfigDataLocation resolved = new ConfigTreeConfigDataLocation(location.substring(PREFIX.length()));
return Collections.singletonList(resolved); return Collections.singletonList(resolved);
} }

@ -46,16 +46,16 @@ import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* {@link PropertySource} backed by a directory that contains files for each value. The * {@link PropertySource} backed by a directory tree that contains files for each value.
* {@link PropertySource} will recursively scan a given source directory and expose a * The {@link PropertySource} will recursively scan a given source directory and expose a
* property for each file found. The property name will be the filename, and the property * property for each file found. The property name will be the filename, and the property
* value will be the contents of the file. * value will be the contents of the file.
* <p> * <p>
* Directories are only scanned when the source is first created. The directory is not * Directories are only scanned when the source is first created. The directory is not
* monitored for updates, so files should not be added or removed. However, the contents * monitored for updates, so files should not be added or removed. However, the contents
* of a file can be updated as long as the property source was created with a * of a file can be updated as long as the property source was created with a
* {@link Option#ALWAYS_READ} option. Nested folders are included in the source, but with * {@link Option#ALWAYS_READ} option. Nested directories are included in the source, but
* a {@code '.'} rather than {@code '/'} used as the path separator. * with a {@code '.'} rather than {@code '/'} used as the path separator.
* <p> * <p>
* Property values are returned as {@link Value} instances which allows them to be treated * Property values are returned as {@link Value} instances which allows them to be treated
* either as an {@link InputStreamSource} or as a {@link CharSequence}. In addition, if * either as an {@link InputStreamSource} or as a {@link CharSequence}. In addition, if
@ -69,7 +69,7 @@ import org.springframework.util.StringUtils;
* @author Phillip Webb * @author Phillip Webb
* @since 2.4.0 * @since 2.4.0
*/ */
public class VolumeMountDirectoryPropertySource extends EnumerablePropertySource<Path> implements OriginLookup<String> { public class ConfigTreePropertySource extends EnumerablePropertySource<Path> implements OriginLookup<String> {
private static final int MAX_DEPTH = 100; private static final int MAX_DEPTH = 100;
@ -80,25 +80,25 @@ public class VolumeMountDirectoryPropertySource extends EnumerablePropertySource
private final Set<Option> options; private final Set<Option> options;
/** /**
* Create a new {@link VolumeMountDirectoryPropertySource} instance. * Create a new {@link ConfigTreePropertySource} instance.
* @param name the name of the property source * @param name the name of the property source
* @param sourceDirectory the underlying source directory * @param sourceDirectory the underlying source directory
*/ */
public VolumeMountDirectoryPropertySource(String name, Path sourceDirectory) { public ConfigTreePropertySource(String name, Path sourceDirectory) {
this(name, sourceDirectory, EnumSet.noneOf(Option.class)); this(name, sourceDirectory, EnumSet.noneOf(Option.class));
} }
/** /**
* Create a new {@link VolumeMountDirectoryPropertySource} instance. * Create a new {@link ConfigTreePropertySource} instance.
* @param name the name of the property source * @param name the name of the property source
* @param sourceDirectory the underlying source directory * @param sourceDirectory the underlying source directory
* @param options the property source options * @param options the property source options
*/ */
public VolumeMountDirectoryPropertySource(String name, Path sourceDirectory, Option... options) { public ConfigTreePropertySource(String name, Path sourceDirectory, Option... options) {
this(name, sourceDirectory, EnumSet.copyOf(Arrays.asList(options))); this(name, sourceDirectory, EnumSet.copyOf(Arrays.asList(options)));
} }
private VolumeMountDirectoryPropertySource(String name, Path sourceDirectory, Set<Option> options) { private ConfigTreePropertySource(String name, Path sourceDirectory, Set<Option> options) {
super(name, sourceDirectory); super(name, sourceDirectory);
Assert.isTrue(Files.exists(sourceDirectory), () -> "Directory '" + sourceDirectory + "' does not exist"); Assert.isTrue(Files.exists(sourceDirectory), () -> "Directory '" + sourceDirectory + "' does not exist");
Assert.isTrue(Files.isDirectory(sourceDirectory), () -> "File '" + sourceDirectory + "' is not a directory"); Assert.isTrue(Files.isDirectory(sourceDirectory), () -> "File '" + sourceDirectory + "' is not a directory");

@ -894,7 +894,7 @@
"value": "classpath:" "value": "classpath:"
}, },
{ {
"value": "volumemount:" "value": "configtree:"
} }
], ],
"providers": [ "providers": [

@ -5,13 +5,13 @@ org.springframework.boot.env.YamlPropertySourceLoader
# ConfigData Location Resolvers # ConfigData Location Resolvers
org.springframework.boot.context.config.ConfigDataLocationResolver=\ org.springframework.boot.context.config.ConfigDataLocationResolver=\
org.springframework.boot.context.config.ResourceConfigDataLocationResolver,\ org.springframework.boot.context.config.ConfigTreeConfigDataLocationResolver,\
org.springframework.boot.context.config.VolumeMountConfigDataLocationResolver org.springframework.boot.context.config.ResourceConfigDataLocationResolver
# ConfigData Loaders # ConfigData Loaders
org.springframework.boot.context.config.ConfigDataLoader=\ org.springframework.boot.context.config.ConfigDataLoader=\
org.springframework.boot.context.config.ResourceConfigDataLoader,\ org.springframework.boot.context.config.ConfigTreeConfigDataLoader,\
org.springframework.boot.context.config.VolumeMountConfigDataLoader org.springframework.boot.context.config.ResourceConfigDataLoader
# Run Listeners # Run Listeners
org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.SpringApplicationRunListener=\

@ -30,14 +30,14 @@ import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Tests for {@link VolumeMountConfigDataLoader}. * Tests for {@link ConfigTreeConfigDataLoader}.
* *
* @author Madhura Bhave * @author Madhura Bhave
* @author Phillip Webb * @author Phillip Webb
*/ */
public class VolumeMountConfigDataLoaderTests { public class ConfigTreeConfigDataLoaderTests {
private VolumeMountConfigDataLoader loader = new VolumeMountConfigDataLoader(); private ConfigTreeConfigDataLoader loader = new ConfigTreeConfigDataLoader();
@TempDir @TempDir
Path directory; Path directory;
@ -47,11 +47,11 @@ public class VolumeMountConfigDataLoaderTests {
File file = this.directory.resolve("hello").toFile(); File file = this.directory.resolve("hello").toFile();
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
FileCopyUtils.copy("world".getBytes(StandardCharsets.UTF_8), file); FileCopyUtils.copy("world".getBytes(StandardCharsets.UTF_8), file);
VolumeMountConfigDataLocation location = new VolumeMountConfigDataLocation(this.directory.toString()); ConfigTreeConfigDataLocation location = new ConfigTreeConfigDataLocation(this.directory.toString());
ConfigData configData = this.loader.load(location); ConfigData configData = this.loader.load(location);
assertThat(configData.getPropertySources().size()).isEqualTo(1); assertThat(configData.getPropertySources().size()).isEqualTo(1);
PropertySource<?> source = configData.getPropertySources().get(0); PropertySource<?> source = configData.getPropertySources().get(0);
assertThat(source.getName()).isEqualTo("Volume mount config '" + this.directory.toString() + "'"); assertThat(source.getName()).isEqualTo("Config tree '" + this.directory.toString() + "'");
assertThat(source.getProperty("hello").toString()).isEqualTo("world"); assertThat(source.getProperty("hello").toString()).isEqualTo("world");
} }

@ -25,20 +25,20 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
* Tests for {@link VolumeMountConfigDataLocationResolver}. * Tests for {@link ConfigTreeConfigDataLocationResolver}.
* *
* @author Madhura Bhave * @author Madhura Bhave
* @author Phillip Webb * @author Phillip Webb
*/ */
class VolumeMountConfigDataLocationResolverTests { class ConfigTreeConfigDataLocationResolverTests {
private VolumeMountConfigDataLocationResolver resolver = new VolumeMountConfigDataLocationResolver(); private ConfigTreeConfigDataLocationResolver resolver = new ConfigTreeConfigDataLocationResolver();
private ConfigDataLocationResolverContext context = mock(ConfigDataLocationResolverContext.class); private ConfigDataLocationResolverContext context = mock(ConfigDataLocationResolverContext.class);
@Test @Test
void isResolvableWhenPrefixMatchesReturnsTrue() { void isResolvableWhenPrefixMatchesReturnsTrue() {
assertThat(this.resolver.isResolvable(this.context, "volumemount:/etc/config")).isTrue(); assertThat(this.resolver.isResolvable(this.context, "configtree:/etc/config")).isTrue();
} }
@Test @Test
@ -49,10 +49,10 @@ class VolumeMountConfigDataLocationResolverTests {
@Test @Test
void resolveReturnsConfigVolumeMountLocation() { void resolveReturnsConfigVolumeMountLocation() {
List<VolumeMountConfigDataLocation> locations = this.resolver.resolve(this.context, "volumemount:/etc/config"); List<ConfigTreeConfigDataLocation> locations = this.resolver.resolve(this.context, "configtree:/etc/config");
assertThat(locations.size()).isEqualTo(1); assertThat(locations.size()).isEqualTo(1);
assertThat(locations).extracting(Object::toString) assertThat(locations).extracting(Object::toString)
.containsExactly("volume mount [" + new File("/etc/config").getAbsolutePath() + "]"); .containsExactly("config tree [" + new File("/etc/config").getAbsolutePath() + "]");
} }
} }

@ -24,37 +24,37 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/** /**
* Tests for {@link VolumeMountConfigDataLocation}. * Tests for {@link ConfigTreeConfigDataLocation}.
* *
* @author Madhura Bhave * @author Madhura Bhave
* @author Phillip Webb * @author Phillip Webb
*/ */
public class VolumeMountConfigDataLocationTests { public class ConfigTreeConfigDataLocationTests {
@Test @Test
void constructorWhenPathIsNullThrowsException() { void constructorWhenPathIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new VolumeMountConfigDataLocation(null)) assertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreeConfigDataLocation(null))
.withMessage("Path must not be null"); .withMessage("Path must not be null");
} }
@Test @Test
void equalsWhenPathIsTheSameReturnsTrue() { void equalsWhenPathIsTheSameReturnsTrue() {
VolumeMountConfigDataLocation location = new VolumeMountConfigDataLocation("/etc/config"); ConfigTreeConfigDataLocation location = new ConfigTreeConfigDataLocation("/etc/config");
VolumeMountConfigDataLocation other = new VolumeMountConfigDataLocation("/etc/config"); ConfigTreeConfigDataLocation other = new ConfigTreeConfigDataLocation("/etc/config");
assertThat(location).isEqualTo(other); assertThat(location).isEqualTo(other);
} }
@Test @Test
void equalsWhenPathIsDifferentReturnsFalse() { void equalsWhenPathIsDifferentReturnsFalse() {
VolumeMountConfigDataLocation location = new VolumeMountConfigDataLocation("/etc/config"); ConfigTreeConfigDataLocation location = new ConfigTreeConfigDataLocation("/etc/config");
VolumeMountConfigDataLocation other = new VolumeMountConfigDataLocation("other-location"); ConfigTreeConfigDataLocation other = new ConfigTreeConfigDataLocation("other-location");
assertThat(location).isNotEqualTo(other); assertThat(location).isNotEqualTo(other);
} }
@Test @Test
void toStringReturnsDescriptiveString() { void toStringReturnsDescriptiveString() {
VolumeMountConfigDataLocation location = new VolumeMountConfigDataLocation("/etc/config"); ConfigTreeConfigDataLocation location = new ConfigTreeConfigDataLocation("/etc/config");
assertThat(location.toString()).isEqualTo("volume mount [" + new File("/etc/config").getAbsolutePath() + "]"); assertThat(location.toString()).isEqualTo("config tree [" + new File("/etc/config").getAbsolutePath() + "]");
} }
} }

@ -26,8 +26,8 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.boot.env.VolumeMountDirectoryPropertySource.Option; import org.springframework.boot.env.ConfigTreePropertySource.Option;
import org.springframework.boot.env.VolumeMountDirectoryPropertySource.Value; import org.springframework.boot.env.ConfigTreePropertySource.Value;
import org.springframework.boot.origin.TextResourceOrigin; import org.springframework.boot.origin.TextResourceOrigin;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.ConfigurableConversionService;
@ -40,32 +40,31 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/** /**
* Tests for {@link VolumeMountDirectoryPropertySource}. * Tests for {@link ConfigTreePropertySource}.
* *
* @author Phillip Webb * @author Phillip Webb
*/ */
class VolumeMountDirectoryPropertySourceTests { class ConfigTreePropertySourceTests {
@TempDir @TempDir
Path directory; Path directory;
@Test @Test
void createWhenNameIsNullThrowsException() { void createWhenNameIsNullThrowsException() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource(null, this.directory))
.isThrownBy(() -> new VolumeMountDirectoryPropertySource(null, this.directory))
.withMessageContaining("name must contain"); .withMessageContaining("name must contain");
} }
@Test @Test
void createWhenSourceIsNullThrowsException() { void createWhenSourceIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new VolumeMountDirectoryPropertySource("test", null)) assertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource("test", null))
.withMessage("Property source must not be null"); .withMessage("Property source must not be null");
} }
@Test @Test
void createWhenSourceDoesNotExistThrowsException() { void createWhenSourceDoesNotExistThrowsException() {
Path missing = this.directory.resolve("missing"); Path missing = this.directory.resolve("missing");
assertThatIllegalArgumentException().isThrownBy(() -> new VolumeMountDirectoryPropertySource("test", missing)) assertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource("test", missing))
.withMessage("Directory '" + missing + "' does not exist"); .withMessage("Directory '" + missing + "' does not exist");
} }
@ -73,45 +72,45 @@ class VolumeMountDirectoryPropertySourceTests {
void createWhenSourceIsFileThrowsException() throws Exception { void createWhenSourceIsFileThrowsException() throws Exception {
Path file = this.directory.resolve("file"); Path file = this.directory.resolve("file");
FileCopyUtils.copy("test".getBytes(StandardCharsets.UTF_8), file.toFile()); FileCopyUtils.copy("test".getBytes(StandardCharsets.UTF_8), file.toFile());
assertThatIllegalArgumentException().isThrownBy(() -> new VolumeMountDirectoryPropertySource("test", file)) assertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource("test", file))
.withMessage("File '" + file + "' is not a directory"); .withMessage("File '" + file + "' is not a directory");
} }
@Test @Test
void getPropertyNamesFromFlatReturnsPropertyNames() throws Exception { void getPropertyNamesFromFlatReturnsPropertyNames() throws Exception {
VolumeMountDirectoryPropertySource propertySource = getFlatPropertySource(); ConfigTreePropertySource propertySource = getFlatPropertySource();
assertThat(propertySource.getPropertyNames()).containsExactly("a", "b", "c"); assertThat(propertySource.getPropertyNames()).containsExactly("a", "b", "c");
} }
@Test @Test
void getPropertyNamesFromNestedReturnsPropertyNames() throws Exception { void getPropertyNamesFromNestedReturnsPropertyNames() throws Exception {
VolumeMountDirectoryPropertySource propertySource = getNestedPropertySource(); ConfigTreePropertySource propertySource = getNestedPropertySource();
assertThat(propertySource.getPropertyNames()).containsExactly("c", "fa.a", "fa.b", "fb.a", "fb.fa.a"); assertThat(propertySource.getPropertyNames()).containsExactly("c", "fa.a", "fa.b", "fb.a", "fb.fa.a");
} }
@Test @Test
void getPropertyNamesWhenLowercaseReturnsPropertyNames() throws Exception { void getPropertyNamesWhenLowercaseReturnsPropertyNames() throws Exception {
addProperty("SpRiNg", "boot"); addProperty("SpRiNg", "boot");
VolumeMountDirectoryPropertySource propertySource = new VolumeMountDirectoryPropertySource("test", ConfigTreePropertySource propertySource = new ConfigTreePropertySource("test", this.directory,
this.directory, Option.USE_LOWERCASE_NAMES); Option.USE_LOWERCASE_NAMES);
assertThat(propertySource.getPropertyNames()).containsExactly("spring"); assertThat(propertySource.getPropertyNames()).containsExactly("spring");
} }
@Test @Test
void getPropertyFromFlatReturnsFileContent() throws Exception { void getPropertyFromFlatReturnsFileContent() throws Exception {
VolumeMountDirectoryPropertySource propertySource = getFlatPropertySource(); ConfigTreePropertySource propertySource = getFlatPropertySource();
assertThat(propertySource.getProperty("b")).hasToString("B"); assertThat(propertySource.getProperty("b")).hasToString("B");
} }
@Test @Test
void getPropertyFromFlatWhenMissingReturnsNull() throws Exception { void getPropertyFromFlatWhenMissingReturnsNull() throws Exception {
VolumeMountDirectoryPropertySource propertySource = getFlatPropertySource(); ConfigTreePropertySource propertySource = getFlatPropertySource();
assertThat(propertySource.getProperty("missing")).isNull(); assertThat(propertySource.getProperty("missing")).isNull();
} }
@Test @Test
void getPropertyFromFlatWhenFileDeletedThrowsException() throws Exception { void getPropertyFromFlatWhenFileDeletedThrowsException() throws Exception {
VolumeMountDirectoryPropertySource propertySource = getFlatPropertySource(); ConfigTreePropertySource propertySource = getFlatPropertySource();
Path b = this.directory.resolve("b"); Path b = this.directory.resolve("b");
Files.delete(b); Files.delete(b);
assertThatIllegalStateException().isThrownBy(() -> propertySource.getProperty("b").toString()) assertThatIllegalStateException().isThrownBy(() -> propertySource.getProperty("b").toString())
@ -120,7 +119,7 @@ class VolumeMountDirectoryPropertySourceTests {
@Test @Test
void getOriginFromFlatReturnsOrigin() throws Exception { void getOriginFromFlatReturnsOrigin() throws Exception {
VolumeMountDirectoryPropertySource propertySource = getFlatPropertySource(); ConfigTreePropertySource propertySource = getFlatPropertySource();
TextResourceOrigin origin = (TextResourceOrigin) propertySource.getOrigin("b"); TextResourceOrigin origin = (TextResourceOrigin) propertySource.getOrigin("b");
assertThat(origin.getResource().getFile()).isEqualTo(this.directory.resolve("b").toFile()); assertThat(origin.getResource().getFile()).isEqualTo(this.directory.resolve("b").toFile());
assertThat(origin.getLocation().getLine()).isEqualTo(0); assertThat(origin.getLocation().getLine()).isEqualTo(0);
@ -129,7 +128,7 @@ class VolumeMountDirectoryPropertySourceTests {
@Test @Test
void getOriginFromFlatWhenMissingReturnsNull() throws Exception { void getOriginFromFlatWhenMissingReturnsNull() throws Exception {
VolumeMountDirectoryPropertySource propertySource = getFlatPropertySource(); ConfigTreePropertySource propertySource = getFlatPropertySource();
assertThat(propertySource.getOrigin("missing")).isNull(); assertThat(propertySource.getOrigin("missing")).isNull();
} }
@ -147,13 +146,13 @@ class VolumeMountDirectoryPropertySourceTests {
@Test @Test
void getPropertyFromNestedReturnsFileContent() throws Exception { void getPropertyFromNestedReturnsFileContent() throws Exception {
VolumeMountDirectoryPropertySource propertySource = getNestedPropertySource(); ConfigTreePropertySource propertySource = getNestedPropertySource();
assertThat(propertySource.getProperty("fb.fa.a")).hasToString("BAA"); assertThat(propertySource.getProperty("fb.fa.a")).hasToString("BAA");
} }
@Test @Test
void getPropertyWhenNotAlwaysReadIgnoresUpdates() throws Exception { void getPropertyWhenNotAlwaysReadIgnoresUpdates() throws Exception {
VolumeMountDirectoryPropertySource propertySource = getNestedPropertySource(); ConfigTreePropertySource propertySource = getNestedPropertySource();
Value v1 = propertySource.getProperty("fa.b"); Value v1 = propertySource.getProperty("fa.b");
Value v2 = propertySource.getProperty("fa.b"); Value v2 = propertySource.getProperty("fa.b");
assertThat(v1).isSameAs(v2); assertThat(v1).isSameAs(v2);
@ -167,8 +166,8 @@ class VolumeMountDirectoryPropertySourceTests {
@Test @Test
void getPropertyWhenAlwaysReadReflectsUpdates() throws Exception { void getPropertyWhenAlwaysReadReflectsUpdates() throws Exception {
addNested(); addNested();
VolumeMountDirectoryPropertySource propertySource = new VolumeMountDirectoryPropertySource("test", ConfigTreePropertySource propertySource = new ConfigTreePropertySource("test", this.directory,
this.directory, Option.ALWAYS_READ); Option.ALWAYS_READ);
Value v1 = propertySource.getProperty("fa.b"); Value v1 = propertySource.getProperty("fa.b");
Value v2 = propertySource.getProperty("fa.b"); Value v2 = propertySource.getProperty("fa.b");
assertThat(v1).isNotSameAs(v2); assertThat(v1).isNotSameAs(v2);
@ -183,21 +182,21 @@ class VolumeMountDirectoryPropertySourceTests {
@Test @Test
void getPropertyWhenLowercaseReturnsValue() throws Exception { void getPropertyWhenLowercaseReturnsValue() throws Exception {
addProperty("SpRiNg", "boot"); addProperty("SpRiNg", "boot");
VolumeMountDirectoryPropertySource propertySource = new VolumeMountDirectoryPropertySource("test", ConfigTreePropertySource propertySource = new ConfigTreePropertySource("test", this.directory,
this.directory, Option.USE_LOWERCASE_NAMES); Option.USE_LOWERCASE_NAMES);
assertThat(propertySource.getProperty("spring")).hasToString("boot"); assertThat(propertySource.getProperty("spring")).hasToString("boot");
} }
private VolumeMountDirectoryPropertySource getFlatPropertySource() throws IOException { private ConfigTreePropertySource getFlatPropertySource() throws IOException {
addProperty("a", "A"); addProperty("a", "A");
addProperty("b", "B"); addProperty("b", "B");
addProperty("c", "C"); addProperty("c", "C");
return new VolumeMountDirectoryPropertySource("test", this.directory); return new ConfigTreePropertySource("test", this.directory);
} }
private VolumeMountDirectoryPropertySource getNestedPropertySource() throws IOException { private ConfigTreePropertySource getNestedPropertySource() throws IOException {
addNested(); addNested();
return new VolumeMountDirectoryPropertySource("test", this.directory); return new ConfigTreePropertySource("test", this.directory);
} }
private void addNested() throws IOException { private void addNested() throws IOException {
Loading…
Cancel
Save