Home / Class/ StandardConfigDataLocationResolverTests Class — spring-boot Architecture

StandardConfigDataLocationResolverTests Class — spring-boot Architecture

Architecture documentation for the StandardConfigDataLocationResolverTests class in StandardConfigDataLocationResolverTests.java from the spring-boot codebase.

Entity Profile

Relationship Graph

Source Code

core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java lines 54–346

class StandardConfigDataLocationResolverTests {

	private StandardConfigDataLocationResolver resolver;

	private final ConfigDataLocationResolverContext context = mock(ConfigDataLocationResolverContext.class);

	private MockEnvironment environment;

	private Binder environmentBinder;

	private final ResourceLoader resourceLoader = new DefaultResourceLoader();

	@BeforeEach
	void setup() {
		this.environment = new MockEnvironment();
		this.environmentBinder = Binder.get(this.environment);
		this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
				this.resourceLoader);
	}

	@Test
	void isResolvableAlwaysReturnsTrue() {
		assertThat(this.resolver.isResolvable(this.context, ConfigDataLocation.of("test"))).isTrue();
	}

	@Test
	@WithResource(name = "configdata/application.properties")
	void resolveWhenLocationIsDirectoryResolvesAllMatchingFilesInDirectory() {
		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/application.properties]");
	}

	@Test
	void resolveWhenLocationIsFileResolvesFile() {
		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("configdata", "application.properties"));
	}

	@Test
	void resolveWhenLocationIsFileAndNoMatchingLoaderThrowsException() {
		ConfigDataLocation location = ConfigDataLocation
			.of("file:src/test/resources/configdata/properties/application.unknown");
		assertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))
			.withMessageStartingWith("Unable to load config data from")
			.satisfies((ex) -> assertThat(ex.getCause()).hasMessageStartingWith("File extension is not known"));
	}

	@Test
	void resolveWhenLocationHasUnknownPrefixAndNoMatchingLoaderThrowsException() {
		ConfigDataLocation location = ConfigDataLocation
			.of("typo:src/test/resources/configdata/properties/application.unknown");
		assertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))
			.withMessageStartingWith("Unable to load config data from")
			.satisfies((ex) -> assertThat(ex.getCause()).hasMessageStartingWith(
					"Incorrect ConfigDataLocationResolver chosen or file extension is not known to any PropertySourceLoader"));
	}

	@Test
	void resolveWhenLocationWildcardIsSpecifiedForClasspathLocationThrowsException() {
		ConfigDataLocation location = ConfigDataLocation.of("classpath*:application.properties");
		assertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))
			.withMessageContaining("Location 'classpath*:application.properties' cannot use classpath wildcards");
	}

	@Test
	void resolveWhenLocationWildcardIsNotBeforeLastSlashThrowsException() {
		ConfigDataLocation location = ConfigDataLocation.of("file:src/test/resources/*/config/");
		assertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))
			.withMessageStartingWith("Location '")
			.withMessageEndingWith("' must end with '*/'");
	}

	@Test
	void createWhenConfigNameHasWildcardThrowsException() {
		this.environment.setProperty("spring.config.name", "*/application");
		assertThatIllegalStateException()
			.isThrownBy(() -> new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
					this.resourceLoader))
			.withMessageStartingWith("Config name '")
			.withMessageEndingWith("' cannot contain '*'");
	}

	@Test
	void resolveWhenLocationHasMultipleWildcardsThrowsException() {
		ConfigDataLocation location = ConfigDataLocation.of("file:src/test/resources/config/**/");
		assertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))
			.withMessageStartingWith("Location '")
			.withMessageEndingWith("' cannot contain multiple wildcards");
	}

	@Test
	@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(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
	@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 resolveWhenLocationIsWildcardDirectoriesSortsAlphabeticallyBasedOnFixedPath(
			@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(resourcesRoot.resolve("config/0-empty/testproperties.properties")),
					filePath(resourcesRoot.resolve("config/1-first/testproperties.properties")),
					filePath(resourcesRoot.resolve("config/2-second/testproperties.properties")));
	}

	@Test
	@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:" + resourcesRoot + "/config/*/testproperties.properties");
		List<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);
		assertThat(locations).hasSize(3);
		assertThat(locations).extracting(Object::toString)
			.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 resolveWhenLocationIsRelativeAndFileResolves() {
		this.environment.setProperty("spring.config.name", "other");
		ConfigDataLocation location = ConfigDataLocation.of("other.properties");
		this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
				this.resourceLoader);
		StandardConfigDataReference parentReference = new StandardConfigDataReference(
				ConfigDataLocation.of("classpath:configdata/properties/application.properties"), null,
				"classpath:configdata/properties/application", null, "properties", new PropertiesPropertySourceLoader(),
				null);
		ClassPathResource parentResource = new ClassPathResource("configdata/properties/application.properties");
		StandardConfigDataResource parent = new StandardConfigDataResource(parentReference, parentResource);
		given(this.context.getParent()).willReturn(parent);
		List<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);
		assertThat(locations).hasSize(1);
		assertThat(locations).extracting(Object::toString)
			.contains("class path resource [configdata/properties/other.properties]");
	}

	@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/");
		this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
				this.resourceLoader);
		StandardConfigDataReference parentReference = new StandardConfigDataReference(
				ConfigDataLocation.of("optional:classpath:configdata/"), null, "classpath:config/specific", null,
				"properties", new PropertiesPropertySourceLoader(), null);
		ClassPathResource parentResource = new ClassPathResource("config/specific.properties");
		StandardConfigDataResource parent = new StandardConfigDataResource(parentReference, parentResource);
		given(this.context.getParent()).willReturn(parent);
		List<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);
		assertThat(locations).hasSize(1);
		assertThat(locations).extracting(Object::toString)
			.contains("class path resource [config/nested/3-third/testproperties.properties]");
	}

	@Test
	void resolveWhenLocationIsRelativeAndNoMatchingLoaderThrowsException() {
		ConfigDataLocation location = ConfigDataLocation.of("application.other");
		StandardConfigDataReference parentReference = new StandardConfigDataReference(
				ConfigDataLocation.of("classpath:configdata/properties/application.properties"), null,
				"configdata/properties/application", null, "properties", new PropertiesPropertySourceLoader(), null);
		ClassPathResource parentResource = new ClassPathResource("configdata/properties/application.properties");
		StandardConfigDataResource parent = new StandardConfigDataResource(parentReference, parentResource);
		given(this.context.getParent()).willReturn(parent);
		assertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))
			.withMessageStartingWith("Unable to load config data from 'application.other'")
			.satisfies((ex) -> assertThat(ex.getCause()).hasMessageStartingWith("File extension is not known"));
	}

	@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);
		assertThat(locations).hasSize(1);
		StandardConfigDataResource resolved = locations.get(0);
		assertThat(resolved.getResource().getFilename()).endsWith("application-props-no-extension");
		ConfigData loaded = new StandardConfigDataLoader().load(mock(ConfigDataLoaderContext.class), resolved);
		PropertySource<?> propertySource = loaded.getPropertySources().get(0);
		assertThat(propertySource.getProperty("withnoextension")).isEqualTo("test");
	}

	@Test
	@WithResource(name = "application-props-no-extension", content = "withnoextension=test")
	void resolveWhenLocationUsesOptionalExplicitExtensionSyntaxResolves() throws Exception {
		ConfigDataLocation location = ConfigDataLocation
			.of("classpath:/application-props-no-extension[extension=.properties]");
		List<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);
		assertThat(locations).hasSize(1);
		StandardConfigDataResource resolved = locations.get(0);
		assertThat(resolved.getResource().getFilename()).endsWith("application-props-no-extension");
		ConfigData loaded = new StandardConfigDataLoader().load(mock(ConfigDataLoaderContext.class), resolved);
		PropertySource<?> propertySource = loaded.getPropertySources().get(0);
		assertThat(propertySource.getProperty("withnoextension")).isEqualTo("test");
	}

	@Test
	@WithResource(name = "utf-8.properties", content = "smiley=😃")
	void resolveWhenLocationUsesEncodingSyntaxResolves() throws IOException {
		ConfigDataLocation location = ConfigDataLocation.of("classpath:utf-8.properties[encoding=utf-8]");
		List<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);
		assertThat(locations).hasSize(1);
		StandardConfigDataResource resolved = locations.get(0);
		assertThat(resolved.getReference().getEncoding()).isEqualTo(StandardCharsets.UTF_8);
		ConfigData loaded = new StandardConfigDataLoader().load(mock(ConfigDataLoaderContext.class), resolved);
		PropertySource<?> propertySource = loaded.getPropertySources().get(0);
		assertThat(propertySource.getProperty("smiley")).isEqualTo("😃");
	}

	@Test
	@WithResource(name = "application-dev.properties")
	void resolveProfileSpecificReturnsProfileSpecificFiles() {
		ConfigDataLocation location = ConfigDataLocation.of("classpath:/");
		this.environment.setActiveProfiles("dev");
		Profiles profiles = new Profiles(this.environment, this.environmentBinder, Collections.emptyList());
		List<StandardConfigDataResource> locations = this.resolver.resolveProfileSpecific(this.context, location,
				profiles);
		assertThat(locations).hasSize(1);
		assertThat(locations).extracting(Object::toString)
			.containsExactly("class path resource [application-dev.properties]");
	}

	@Test
	void resolveProfileSpecificWhenLocationIsFileReturnsEmptyList() {
		ConfigDataLocation location = ConfigDataLocation.of("classpath:/configdata/properties/application.properties");
		Profiles profiles = mock(Profiles.class);
		given(profiles.iterator()).willReturn(Collections.emptyIterator());
		given(profiles.getActive()).willReturn(Collections.singletonList("dev"));
		List<StandardConfigDataResource> locations = this.resolver.resolveProfileSpecific(this.context, location,
				profiles);
		assertThat(locations).isEmpty();
	}

	@Test
	void resolveWhenOptionalAndLoaderIsUnknownShouldNotFail() {
		ConfigDataLocation location = ConfigDataLocation.of("optional:some-unknown-loader:dummy.properties");
		assertThatNoException().isThrownBy(() -> this.resolver.resolve(this.context, location));
	}

	@Test
	void resolveWhenOptionalAndLoaderIsUnknownAndExtensionIsUnknownShouldNotFail() {
		ConfigDataLocation location = ConfigDataLocation
			.of("optional:some-unknown-loader:dummy.some-unknown-extension");
		assertThatNoException().isThrownBy(() -> this.resolver.resolve(this.context, location));
	}

	@Test
	void resolveWhenOptionalAndExtensionIsUnknownShouldNotFail() {
		ConfigDataLocation location = ConfigDataLocation.of("optional:file:dummy.some-unknown-extension");
		assertThatNoException().isThrownBy(() -> this.resolver.resolve(this.context, location));
	}

	private String filePath(String... components) {
		return "file [" + String.join(File.separator, components) + "]";
	}

	private String filePath(Path path) {
		return "file [%s]".formatted(path);
	}

}

Domain

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free