feat(config-server): add MongoDB environment repository support (#2390)

* feat(config-server): add MongoDB environment repository support

This commit introduces MongoDB as a new backend option for the Spring Cloud Config Server, enabling users to store and manage their configuration properties in a MongoDB database.

* resolve pr comments

* add documentation for mongodb backend

* resolve comments
This commit is contained in:
Alexandros Pappas
2024-10-02 20:36:29 +02:00
committed by GitHub
parent 3c69958559
commit 634f46b424
10 changed files with 699 additions and 1 deletions

View File

@@ -15,6 +15,7 @@
*** xref:server/environment-repository/aws-parameter-store-backend.adoc[]
*** xref:server/environment-repository/aws-secrets-manager-backend.adoc[]
*** xref:server/environment-repository/credhub-backend.adoc[]
*** xref:server/environment-repository/mongo-backend.adoc[]
*** xref:server/environment-repository/composite-repositories.adoc[]
*** xref:server/environment-repository/custom-enviroment-repository.adoc[]
*** xref:server/environment-repository/property-overrides.adoc[]

View File

@@ -0,0 +1,58 @@
[[mongo-backend]]
= MongoDB Backend
:page-section-summary-toc: 1
Spring Cloud Config Server supports MongoDB as a backend for configuration properties.
You can enable this feature by adding `spring-boot-starter-data-mongodb` to the classpath and using the `mongodb` profile.
[source,xml,indent=0]
.pom.xml
----
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
----
Configure your application's `application.properties` or `application.yml` to point to your MongoDB instance:
[source,yaml]
----
spring:
profiles:
active: mongodb
data:
mongodb:
database: your-database-name
port: '27017'
host: localhost
----
The configuration properties should be stored in documents within the `properties` collection. Each document represents a set of properties for a given application, profile, and label.
Example MongoDB document:
[source,json]
----
{
"application": "myapp",
"profile": "development",
"label": "master",
"properties": {
"property1": "value1",
"property2": "value2"
}
}
----
You can disable autoconfiguration for `MongoDbEnvironmentRepository` by setting the `spring.cloud.config.server.mongodb.enabled` property to `false`.
The default values for MongoDB backend configuration are as follows:
- **Collection Name:** `"properties"` (Name of the MongoDB collection to query for configuration properties.)
- **Default Label:** `"master"` (Default label to use if none is specified.)
NOTE: You can change these defaults by setting `spring.cloud.config.server.mongodb.collection` and `spring.cloud.config.server.mongodb.defaultLabel` in your application's configuration.

View File

@@ -147,6 +147,11 @@
<artifactId>google-auth-library-oauth2-http</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
@@ -232,6 +237,16 @@
<artifactId>spring-core-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mongodb</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>

View File

@@ -69,6 +69,9 @@ import org.springframework.cloud.config.server.environment.HttpRequestConfigToke
import org.springframework.cloud.config.server.environment.JdbcEnvironmentProperties;
import org.springframework.cloud.config.server.environment.JdbcEnvironmentRepository;
import org.springframework.cloud.config.server.environment.JdbcEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.MongoDbEnvironmentProperties;
import org.springframework.cloud.config.server.environment.MongoDbEnvironmentRepository;
import org.springframework.cloud.config.server.environment.MongoDbEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentProperties;
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository;
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepositoryFactory;
@@ -99,6 +102,7 @@ import org.springframework.context.annotation.Profile;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.credhub.core.CredHubOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.vault.core.VaultTemplate;
@@ -112,19 +116,21 @@ import org.springframework.vault.core.VaultTemplate;
* @author Scott Frederick
* @author Tejas Pandilwar
* @author Iulian Antohe
* @author Alexandros Pappas
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ SvnKitEnvironmentProperties.class, CredhubEnvironmentProperties.class,
JdbcEnvironmentProperties.class, NativeEnvironmentProperties.class, VaultEnvironmentProperties.class,
RedisEnvironmentProperties.class, AwsS3EnvironmentProperties.class,
AwsSecretsManagerEnvironmentProperties.class, AwsParameterStoreEnvironmentProperties.class,
GoogleSecretManagerEnvironmentProperties.class })
GoogleSecretManagerEnvironmentProperties.class, MongoDbEnvironmentProperties.class })
@Import({ CompositeRepositoryConfiguration.class, JdbcRepositoryConfiguration.class, VaultConfiguration.class,
VaultRepositoryConfiguration.class, SpringVaultRepositoryConfiguration.class, CredhubConfiguration.class,
CredhubRepositoryConfiguration.class, SvnRepositoryConfiguration.class, NativeRepositoryConfiguration.class,
GitRepositoryConfiguration.class, RedisRepositoryConfiguration.class, GoogleCloudSourceConfiguration.class,
AwsS3RepositoryConfiguration.class, AwsSecretsManagerRepositoryConfiguration.class,
AwsParameterStoreRepositoryConfiguration.class, GoogleSecretManagerRepositoryConfiguration.class,
MongoRepositoryConfiguration.class,
// DefaultRepositoryConfiguration must be last
DefaultRepositoryConfiguration.class })
public class EnvironmentRepositoryConfiguration {
@@ -378,6 +384,19 @@ public class EnvironmentRepositoryConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MongoTemplate.class)
@ConditionalOnProperty(value = "spring.cloud.config.server.mongodb.enabled", matchIfMissing = true)
static class MongoDbFactoryConfig {
@Bean
@ConditionalOnBean(MongoTemplate.class)
public MongoDbEnvironmentRepositoryFactory mongoDbEnvironmentRepositoryFactory(MongoTemplate mongoTemplate) {
return new MongoDbEnvironmentRepositoryFactory(mongoTemplate);
}
}
}
@Configuration(proxyBeanMethods = false)
@@ -579,3 +598,18 @@ class GoogleSecretManagerRepositoryConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@Profile("mongodb")
@ConditionalOnClass(MongoTemplate.class)
@ConditionalOnProperty(value = "spring.cloud.config.server.mongodb.enabled", matchIfMissing = true)
class MongoRepositoryConfiguration {
@Bean
@ConditionalOnBean(MongoTemplate.class)
public MongoDbEnvironmentRepository mongoDbEnvironmentRepository(MongoDbEnvironmentRepositoryFactory factory,
MongoDbEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2018-2019 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.cloud.config.server.environment;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.config.server.support.EnvironmentRepositoryProperties;
import org.springframework.core.Ordered;
/**
* Properties related to MongoDB environment repository.
*
* @author Alexandros Pappas
*/
@ConfigurationProperties("spring.cloud.config.server.mongodb")
public class MongoDbEnvironmentProperties implements EnvironmentRepositoryProperties {
/**
* Flag to indicate that MongoDB environment repository configuration is enabled.
*/
private boolean enabled = true;
/**
* Order of the MongoDB environment repository.
*/
private int order = Ordered.LOWEST_PRECEDENCE - 10;
/**
* Name of the MongoDB collection to query for configuration properties.
*/
private String collection = "properties";
/**
* Flag to determine how to handle query exceptions.
*/
private boolean failOnError = true;
/**
* Default label to use if none is specified.
*/
private String defaultLabel = "master";
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public int getOrder() {
return order;
}
@Override
public void setOrder(int order) {
this.order = order;
}
public String getCollection() {
return collection;
}
public void setCollection(String collection) {
this.collection = collection;
}
public boolean isFailOnError() {
return failOnError;
}
public void setFailOnError(boolean failOnError) {
this.failOnError = failOnError;
}
public String getDefaultLabel() {
return defaultLabel;
}
public void setDefaultLabel(String defaultLabel) {
this.defaultLabel = defaultLabel;
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2018-2019 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.cloud.config.server.environment;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.mongodb.MongoException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.core.Ordered;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.StringUtils;
/**
* @author Alexandros Pappas
*/
public class MongoDbEnvironmentRepository implements EnvironmentRepository, Ordered {
private static final Log logger = LogFactory.getLog(JdbcEnvironmentRepository.class);
private final MongoTemplate mongoTemplate;
private final MongoDbEnvironmentProperties properties;
public MongoDbEnvironmentRepository(MongoTemplate mongoTemplate, MongoDbEnvironmentProperties properties) {
this.mongoTemplate = mongoTemplate;
this.properties = properties;
}
@Override
public Environment findOne(String application, String profile, String label) {
label = StringUtils.hasText(label) ? label : this.properties.getDefaultLabel();
profile = StringUtils.hasText(profile) ? profile : "default";
// Prepare the environment with applications and profiles
String[] profilesArray = StringUtils.commaDelimitedListToStringArray(profile);
Environment environment = new Environment(application, profilesArray, label, null, null);
// Prepend "application," to config if not already present
String config = application.startsWith("application") ? application : "application," + application;
List<String> applications = Arrays.stream(StringUtils.commaDelimitedListToStringArray(config)).distinct()
.collect(Collectors.toList());
List<String> profiles = Arrays.stream(profilesArray).distinct().collect(Collectors.toList());
// Reverse for the intended processing order
Collections.reverse(applications);
Collections.reverse(profiles);
// Add property sources for each combination of application and profile
for (String env : profiles) {
for (String app : applications) {
addPropertySource(environment, app, env, label);
}
}
// add properties without profile, equivalent to foo.yml, application.yml
for (String app : applications) {
addPropertySource(environment, app, null, label);
}
return environment;
}
private void addPropertySource(Environment environment, String application, String profile, String label) {
try {
Criteria criteria = Criteria.where("application").is(application).and("label").is(label);
if (profile != null) {
criteria = criteria.and("profile").is(profile);
}
else {
// Handling properties without profile by explicitly looking for them
criteria = criteria.andOperator(Criteria.where("profile").is(null));
}
Query query = new Query(criteria);
List<Map> propertyMaps = this.mongoTemplate.find(query, Map.class, this.properties.getCollection());
for (Map propertyMap : propertyMaps) {
String propertySourceName = (profile != null) ? application + "-" + profile : application;
@SuppressWarnings("unchecked")
Map<String, Object> source = (Map<String, Object>) propertyMap.get("properties");
if (source != null && !source.isEmpty()) {
environment.add(new PropertySource(propertySourceName, source));
}
}
}
catch (DataAccessException | MongoException e) {
if (!this.properties.isFailOnError()) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to retrieve configuration from MongoDB", e);
}
}
else {
throw e;
}
}
}
@Override
public int getOrder() {
return this.properties.getOrder();
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2018-2019 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.cloud.config.server.environment;
import org.springframework.data.mongodb.core.MongoTemplate;
/**
* Factory for creating instances of MongoDbEnvironmentRepository.
*
* @author Alexandros Pappas
*/
public class MongoDbEnvironmentRepositoryFactory
implements EnvironmentRepositoryFactory<MongoDbEnvironmentRepository, MongoDbEnvironmentProperties> {
private final MongoTemplate mongoTemplate;
public MongoDbEnvironmentRepositoryFactory(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@Override
public MongoDbEnvironmentRepository build(MongoDbEnvironmentProperties environmentProperties) {
return new MongoDbEnvironmentRepository(this.mongoTemplate, environmentProperties);
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2018-2019 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.cloud.config.server.environment;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
import org.springframework.cloud.config.server.test.TestConfigServerApplication;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests to verify MongoDbEnvironmentRepository configuration.
*
* @author Alexandros Pappas
*/
public class MongoDbEnvironmentRepositoryConfigurationTests {
@Test
public void mongoDbEnvironmentRepositoryBeansConfiguredWhenDefault() {
new WebApplicationContextRunner().withUserConfiguration(TestConfigServerApplication.class)
.withPropertyValues("spring.profiles.active=test,mongodb", "spring.main.web-application-type=none")
.run(context -> {
assertThat(context).hasSingleBean(MongoDbEnvironmentRepositoryFactory.class);
assertThat(context).hasSingleBean(MongoDbEnvironmentRepository.class);
});
}
@Test
public void mongoDbEnvironmentRepositoryBeansConfiguredWhenEnabled() throws IOException {
getApplicationContextWithMongoDbEnabled(true, context -> {
assertThat(context).hasSingleBean(MongoDbEnvironmentRepositoryFactory.class);
assertThat(context).hasSingleBean(MongoDbEnvironmentRepository.class);
});
}
@Test
public void mongoDbEnvironmentRepositoryFactoryNotConfiguredWhenDisabled() throws IOException {
getApplicationContextWithMongoDbEnabled(false,
context -> assertThat(context).doesNotHaveBean(MongoDbEnvironmentRepositoryFactory.class));
}
@Test
public void mongoDbEnvironmentRepositoryNotConfiguredWhenDisabled() throws IOException {
getApplicationContextWithMongoDbEnabled(false,
context -> assertThat(context).doesNotHaveBean(MongoDbEnvironmentRepository.class));
}
private void getApplicationContextWithMongoDbEnabled(boolean mongoDbEnabled,
ContextConsumer<? super AssertableWebApplicationContext> consumer) throws IOException {
String uri = ConfigServerTestUtils.prepareLocalRepo();
new WebApplicationContextRunner().withUserConfiguration(TestConfigServerApplication.class)
.withPropertyValues("spring.profiles.active=test,mongodb", "spring.main.web-application-type=none",
"spring.cloud.config.server.git.uri:" + uri,
"spring.cloud.config.server.mongodb.enabled:" + mongoDbEnabled)
.run(consumer);
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright 2018-2019 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.cloud.config.server.environment;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import com.mongodb.MongoException;
import com.mongodb.MongoTimeoutException;
import org.bson.Document;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import wiremock.com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
/**
* @author Alexandros Pappas
*/
@SpringBootTest
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@ActiveProfiles("mongodb")
@Testcontainers
@Tag("DockerRequired")
public class MongoDbEnvironmentRepositoryTests {
@Container
@ServiceConnection
static MongoDBContainer mongoContainer = new MongoDBContainer("mongo:5.0");
@Autowired
private MongoTemplate mongoTemplate;
@BeforeEach
void setup() throws IOException {
mongoContainer.start();
mongoTemplate.dropCollection("properties");
InputStream inputStream = new ClassPathResource("/data-mongo.json").getInputStream();
String json = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
List<Document> documents = Arrays.asList(new ObjectMapper().readValue(json, Document[].class));
mongoTemplate.getCollection("properties").insertMany(documents);
}
@Test
public void basicProperties() {
MongoDbEnvironmentProperties properties = new MongoDbEnvironmentProperties();
Environment env = new MongoDbEnvironmentRepository(mongoTemplate, properties).findOne("foo", "bar", "");
assertThat(env.getName()).isEqualTo("foo");
assertThat(env.getProfiles()).isEqualTo(new String[] { "bar" });
assertThat(env.getLabel()).isEqualTo("master");
assertThat(env.getPropertySources()).isNotEmpty();
assertThat(env.getPropertySources().get(0).getName()).isEqualTo("foo-bar");
assertThat(env.getPropertySources().get(0).getSource().get("a_b_c")).isEqualTo("foo-bar");
assertThat(env.getPropertySources().get(1).getName()).isEqualTo("application-bar");
assertThat(env.getPropertySources().get(1).getSource().get("a_b_c")).isEqualTo("application-bar");
assertThat(env.getPropertySources().get(2).getName()).isEqualTo("foo");
assertThat(env.getPropertySources().get(2).getSource().get("a_b_c")).isEqualTo("foo-null");
assertThat(env.getPropertySources().get(3).getName()).isEqualTo("application");
assertThat(env.getPropertySources().get(3).getSource().get("a_b_c")).isEqualTo("application-null");
}
@Test
public void testDefaultProfile() {
MongoDbEnvironmentProperties properties = new MongoDbEnvironmentProperties();
Environment env = new MongoDbEnvironmentRepository(mongoTemplate, properties).findOne("foo", "", "");
assertThat(env.getName()).isEqualTo("foo");
assertThat(env.getProfiles()).isEqualTo(new String[] { "default" });
assertThat(env.getLabel()).isEqualTo("master");
assertThat(env.getPropertySources()).isNotEmpty();
assertThat(env.getPropertySources().get(0).getName()).isEqualTo("foo-default");
assertThat(env.getPropertySources().get(0).getSource().get("a_b_c")).isEqualTo("foo-default");
assertThat(env.getPropertySources().get(1).getName()).isEqualTo("application-default");
assertThat(env.getPropertySources().get(1).getSource().get("a_b_c")).isEqualTo("application-default");
assertThat(env.getPropertySources().get(2).getName()).isEqualTo("foo");
assertThat(env.getPropertySources().get(2).getSource().get("a_b_c")).isEqualTo("foo-null");
assertThat(env.getPropertySources().get(3).getName()).isEqualTo("application");
assertThat(env.getPropertySources().get(3).getSource().get("a_b_c")).isEqualTo("application-null");
}
@Test
public void testProfileNotExist() {
MongoDbEnvironmentProperties properties = new MongoDbEnvironmentProperties();
Environment env = new MongoDbEnvironmentRepository(mongoTemplate, properties).findOne("foo", "not_exist", "");
assertThat(env.getName()).isEqualTo("foo");
assertThat(env.getProfiles()).isEqualTo(new String[] { "not_exist" });
assertThat(env.getLabel()).isEqualTo("master");
assertThat(env.getPropertySources()).isNotEmpty();
assertThat(env.getPropertySources().get(0).getName()).isEqualTo("foo");
assertThat(env.getPropertySources().get(0).getSource().get("a_b_c")).isEqualTo("foo-null");
assertThat(env.getPropertySources().get(1).getName()).isEqualTo("application");
assertThat(env.getPropertySources().get(1).getSource().get("a_b_c")).isEqualTo("application-null");
}
@Test
public void testApplicationNotExist() {
MongoDbEnvironmentProperties properties = new MongoDbEnvironmentProperties();
Environment env = new MongoDbEnvironmentRepository(mongoTemplate, properties).findOne("not_exist", "bar", "");
assertThat(env.getName()).isEqualTo("not_exist");
assertThat(env.getProfiles()).isEqualTo(new String[] { "bar" });
assertThat(env.getLabel()).isEqualTo("master");
assertThat(env.getPropertySources()).isNotEmpty();
assertThat(env.getPropertySources().get(0).getName()).isEqualTo("application-bar");
assertThat(env.getPropertySources().get(0).getSource().get("a_b_c")).isEqualTo("application-bar");
assertThat(env.getPropertySources().get(1).getName()).isEqualTo("application");
assertThat(env.getPropertySources().get(1).getSource().get("a_b_c")).isEqualTo("application-null");
}
@Test
public void testApplicationProfileBothNotExist() {
MongoDbEnvironmentProperties properties = new MongoDbEnvironmentProperties();
Environment env = new MongoDbEnvironmentRepository(mongoTemplate, properties).findOne("not_exist", "not_exist",
"");
assertThat(env.getName()).isEqualTo("not_exist");
assertThat(env.getProfiles()).isEqualTo(new String[] { "not_exist" });
assertThat(env.getLabel()).isEqualTo("master");
assertThat(env.getPropertySources()).isNotEmpty();
assertThat(env.getPropertySources().get(0).getName()).isEqualTo("application");
assertThat(env.getPropertySources().get(0).getSource().get("a_b_c")).isEqualTo("application-null");
}
@Test
public void testCustomLabel() {
MongoDbEnvironmentProperties properties = new MongoDbEnvironmentProperties();
properties.setDefaultLabel("main");
Environment env = new MongoDbEnvironmentRepository(mongoTemplate, properties).findOne("foo", "bar", "");
assertThat(env.getName()).isEqualTo("foo");
assertThat(env.getProfiles()).isEqualTo(new String[] { "bar" });
assertThat(env.getLabel()).isEqualTo("main");
assertThat(env.getPropertySources()).isNotEmpty();
assertThat(env.getPropertySources().get(0).getName()).isEqualTo("foo-bar");
assertThat(env.getPropertySources().get(0).getSource().get("a_b_c")).isEqualTo("foo-bar");
assertThat(env.getPropertySources().get(1).getName()).isEqualTo("application-bar");
assertThat(env.getPropertySources().get(1).getSource().get("a_b_c")).isEqualTo("application-bar");
}
@Test
public void testFailOnError() {
MongoTemplate failingMongoTemplate = Mockito.spy(mongoTemplate);
Mockito.doThrow(new MongoTimeoutException("Timed out after 30000 ms while waiting for a server."))
.when(failingMongoTemplate).find(any(Query.class), any(), anyString());
MongoDbEnvironmentRepository repository = new MongoDbEnvironmentRepository(failingMongoTemplate,
new MongoDbEnvironmentProperties());
assertThatThrownBy(() -> repository.findOne("foo", "bar", "")).isInstanceOf(MongoException.class)
.hasMessageContaining("Timed out after 30000 ms while waiting for a server.");
}
}

View File

@@ -0,0 +1,66 @@
[
{
"application": "foo",
"profile": "bar",
"label": "master",
"properties": {
"a_b_c": "foo-bar"
}
},
{
"application": "foo",
"profile": "default",
"label": "master",
"properties": {
"a_b_c": "foo-default"
}
},
{
"application": "foo",
"profile": null,
"label": "master",
"properties": {
"a_b_c": "foo-null"
}
},
{
"application": "application",
"profile": "bar",
"label": "master",
"properties": {
"a_b_c": "application-bar"
}
},
{
"application": "application",
"profile": "default",
"label": "master",
"properties": {
"a_b_c": "application-default"
}
},
{
"application": "application",
"profile": null,
"label": "master",
"properties": {
"a_b_c": "application-null"
}
},
{
"application": "foo",
"profile": "bar",
"label": "main",
"properties": {
"a_b_c": "foo-bar"
}
},
{
"application": "application",
"profile": "bar",
"label": "main",
"properties": {
"a_b_c": "application-bar"
}
}
]