Merge pull request #595 from ryanjbaxter/composite-envrepo-495

Support for composite environment repos
This commit is contained in:
Ryan Baxter
2016-12-21 13:31:24 -05:00
committed by GitHub
29 changed files with 630 additions and 42 deletions

View File

@@ -556,6 +556,56 @@ $ vault write secret/application foo=bar baz=bam
All applications using the config server will have the properties
`foo` and `baz` available to them.
==== Composite Environment Repositories
In some scenarios you may wish to pull configuration data from multiple
environment repositories. To do this just enable
multiple profiles in your config server's application properties or YAML file.
If, for example, you want to pull configuration data from a Git repository
as well as a SVN repository you would set the following properties for your
configuration server.
[source,yaml]
----
spring:
profiles:
active: git, svn
cloud:
config:
server:
svn:
uri: file:///path/to/svn/repo
order: 2
git:
uri: file:///path/to/git/repo
order: 1
----
In addition to each repo specifying a URI, you can also specify an `order` property.
The `order` property allows you to specify the priority order for all your repositories.
The lower the numerical value of the `order` property the higher priority it will have.
The priority order of a repository will help resolve any potential conflicts between
repositories that contain values for the same properties.
NOTE: Any type of failure when retrieving values from an environment repositoy
will result in a failure for the entire composite environment.
NOTE: When using a composite environment it is important that all repos contain
the same label(s). If you have an environment similar to the one above and you request
configuration data with the label `master` but the SVN
repo does not contain a branch called `master` the entire request will fail.
===== Custom Composite Environment Repositories
It is also possible to provide your own `EnvironmentRepository` bean
to be included as part of a composite environment in addition to
using one of the environment repositories from Spring Cloud. To do this your bean
must implement the `EnvironmentRepository` interface. If you would like to control
the priority of you custom `EnvironmentRepository` within the composite
environment you should also implement the `Ordered` interface and override the
`getOrdered` method. If you do not implement the `Ordered` interface than your
`EnvironmentRepository` will be given the lowest priority.
==== Property Overrides
The Config Server has an "overrides" feature that allows the operator

View File

@@ -76,6 +76,10 @@ public class Environment {
this.propertySources.add(propertySource);
}
public void addAll(List<PropertySource> propertySources) {
this.propertySources.addAll(propertySources);
}
public void addFirst(PropertySource propertySource) {
this.propertySources.add(0, propertySource);
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2013-2016 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
*
* http://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.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.config.server.environment.CompositeEnvironmentRepository;
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
import org.springframework.cloud.config.server.environment.SearchPathCompositeEnvironmentRepository;
import org.springframework.cloud.config.server.environment.SearchPathLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* @author Ryan Baxter
*/
@Configuration
public class CompositeConfiguration {
private List<EnvironmentRepository> environmentRepos = new ArrayList<>();
@Bean
@Primary
@ConditionalOnBean(SearchPathLocator.class)
public SearchPathCompositeEnvironmentRepository searchPathCompositeEnvironmentRepository() {
return new SearchPathCompositeEnvironmentRepository(environmentRepos);
}
@Bean
@Primary
@ConditionalOnMissingBean(SearchPathLocator.class)
public CompositeEnvironmentRepository compositeEnvironmentRepository() {
return new CompositeEnvironmentRepository(environmentRepos);
}
@Autowired
public void setEnvironmentRepos(List<EnvironmentRepository> repos) {
this.environmentRepos = repos;
}
}

View File

@@ -28,7 +28,7 @@ import org.springframework.context.annotation.Import;
@Configuration
@ConditionalOnBean(ConfigServerConfiguration.Marker.class)
@EnableConfigurationProperties(ConfigServerProperties.class)
@Import({ EnvironmentRepositoryConfiguration.class, ResourceRepositoryConfiguration.class,
@Import({ EnvironmentRepositoryConfiguration.class, CompositeConfiguration.class, ResourceRepositoryConfiguration.class,
ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class })
public class ConfigServerAutoConfiguration {

View File

@@ -20,7 +20,6 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.config.server.environment.ConsulEnvironmentWatch;
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
import org.springframework.cloud.config.server.environment.EnvironmentWatch;
@@ -36,10 +35,10 @@ import org.springframework.web.client.RestTemplate;
/**
* @author Dave Syer
* @author Ryan Baxter
*
*/
@Configuration
@ConditionalOnMissingBean(EnvironmentRepository.class)
public class EnvironmentRepositoryConfiguration {
@Bean
@@ -48,6 +47,26 @@ public class EnvironmentRepositoryConfiguration {
return new ConfigServerHealthIndicator(repository);
}
@Configuration
@ConditionalOnMissingBean(EnvironmentRepository.class)
protected static class DefaultRepositoryConfiguration {
@Autowired
private ConfigurableEnvironment environment;
@Autowired
private ConfigServerProperties server;
@Bean
public MultipleJGitEnvironmentRepository defaultEnvironmentRepository() {
MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment);
if (this.server.getDefaultLabel()!=null) {
repository.setDefaultLabel(this.server.getDefaultLabel());
}
return repository;
}
}
@Configuration
@Profile("native")
protected static class NativeRepositoryConfiguration {
@@ -56,31 +75,14 @@ public class EnvironmentRepositoryConfiguration {
private ConfigurableEnvironment environment;
@Bean
public NativeEnvironmentRepository environmentRepository() {
public NativeEnvironmentRepository nativeEnvironmentRepository() {
return new NativeEnvironmentRepository(this.environment);
}
}
@Configuration
@ConditionalOnMissingBean(EnvironmentRepository.class)
protected static class GitRepositoryConfiguration {
@Autowired
private ConfigurableEnvironment environment;
@Autowired
private ConfigServerProperties server;
@Bean
public MultipleJGitEnvironmentRepository environmentRepository() {
MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment);
if (this.server.getDefaultLabel()!=null) {
repository.setDefaultLabel(this.server.getDefaultLabel());
}
return repository;
}
}
@Profile("git")
protected static class GitRepositoryConfiguration extends DefaultRepositoryConfiguration {}
@Configuration
@Profile("subversion")
@@ -92,7 +94,7 @@ public class EnvironmentRepositoryConfiguration {
private ConfigServerProperties server;
@Bean
public SvnKitEnvironmentRepository environmentRepository() {
public SvnKitEnvironmentRepository svnKitEnvironmentRepository() {
SvnKitEnvironmentRepository repository = new SvnKitEnvironmentRepository(this.environment);
if (this.server.getDefaultLabel()!=null) {
repository.setDefaultLabel(this.server.getDefaultLabel());
@@ -105,7 +107,7 @@ public class EnvironmentRepositoryConfiguration {
@Profile("vault")
protected static class VaultConfiguration {
@Bean
public EnvironmentRepository environmentRepository(HttpServletRequest request, EnvironmentWatch watch) {
public VaultEnvironmentRepository valutEnvironmentRepository(HttpServletRequest request, EnvironmentWatch watch) {
return new VaultEnvironmentRepository(request, watch, new RestTemplate());
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.config.server.environment;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.support.AbstractScmAccessor;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
/**
@@ -25,9 +26,10 @@ import org.springframework.core.env.ConfigurableEnvironment;
*
*/
public abstract class AbstractScmEnvironmentRepository extends AbstractScmAccessor
implements EnvironmentRepository, SearchPathLocator {
implements EnvironmentRepository, SearchPathLocator, Ordered {
private EnvironmentCleaner cleaner = new EnvironmentCleaner();
private int order = Ordered.LOWEST_PRECEDENCE;
public AbstractScmEnvironmentRepository(ConfigurableEnvironment environment) {
super(environment);
@@ -46,4 +48,12 @@ public abstract class AbstractScmEnvironmentRepository extends AbstractScmAccess
getUri());
}
@Override
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2013-2016 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
*
* http://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.Collections;
import java.util.List;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.core.OrderComparator;
/**
* An {@link EnvironmentRepository} composed of multiple ordered {@link EnvironmentRepository}s.
* @author Ryan Baxter
*/
public class CompositeEnvironmentRepository implements EnvironmentRepository {
protected List<EnvironmentRepository> environmentRepositories;
/**
* Creates a new {@link CompositeEnvironmentRepository}.
* @param environmentRepositories The list of {@link EnvironmentRepository}s to create the composite from.
*/
public CompositeEnvironmentRepository(List<EnvironmentRepository> environmentRepositories) {
//Sort the environment repositories by the priority
Collections.sort(environmentRepositories, OrderComparator.INSTANCE);
this.environmentRepositories = environmentRepositories;
}
@Override
public Environment findOne(String application, String profile, String label) {
Environment env = new Environment(application, new String[]{profile}, label, null, null);
for(EnvironmentRepository repo : environmentRepositories) {
env.addAll(repo.findOne(application, profile, label).getPropertySources());
}
return env;
}
}

View File

@@ -293,4 +293,8 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
}
@Override
public void setOrder(int order) {
super.setOrder(order);
}
}

View File

@@ -32,6 +32,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
@@ -47,8 +48,7 @@ import org.springframework.util.StringUtils;
* @author Roy Clarkson
*/
@ConfigurationProperties("spring.cloud.config.server.native")
public class NativeEnvironmentRepository
implements EnvironmentRepository, SearchPathLocator {
public class NativeEnvironmentRepository implements EnvironmentRepository, SearchPathLocator, Ordered {
private static Log logger = LogFactory.getLog(NativeEnvironmentRepository.class);
@@ -75,6 +75,8 @@ public class NativeEnvironmentRepository
private ConfigurableEnvironment environment;
private int order = Ordered.LOWEST_PRECEDENCE;
public NativeEnvironmentRepository(ConfigurableEnvironment environment) {
this.environment = environment;
}
@@ -275,4 +277,12 @@ public class NativeEnvironmentRepository
&& !location.endsWith(".yml") && !location.endsWith(".yaml");
}
@Override
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2013-2016 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
*
* http://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.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A {@link CompositeEnvironmentRepository} which implements {@link SearchPathLocator}.
* @author Ryan Baxter
*/
public class SearchPathCompositeEnvironmentRepository extends CompositeEnvironmentRepository implements SearchPathLocator {
/**
* Creates a new {@link SearchPathCompositeEnvironmentRepository}.
* @param environmentRepositories The {@link EnvironmentRepository}s to create this composite from.
*/
public SearchPathCompositeEnvironmentRepository(List<EnvironmentRepository> environmentRepositories) {
super(environmentRepositories);
}
@Override
public Locations getLocations(String application, String profile, String label) {
List<String> locations = new ArrayList<>();
for(EnvironmentRepository repo : this.environmentRepositories) {
if(repo instanceof SearchPathLocator) {
locations.addAll(Arrays.asList(((SearchPathLocator) repo).getLocations(application, profile, label).getLocations()));
}
}
return new Locations(application, profile, label, null, locations.toArray(new String[locations.size()]));
}
}

View File

@@ -64,6 +64,10 @@ public class SvnKitEnvironmentRepository extends AbstractScmEnvironmentRepositor
this.defaultLabel = defaultLabel;
}
public SvnKitEnvironmentRepository(ConfigurableEnvironment environment) {
super(environment);
}
@Override
public synchronized Locations getLocations(String application, String profile,
String label) {
@@ -168,10 +172,6 @@ public class SvnKitEnvironmentRepository extends AbstractScmEnvironmentRepositor
}
public SvnKitEnvironmentRepository(ConfigurableEnvironment environment) {
super(environment);
}
@Override
protected File getWorkingDirectory() {
return this.getBasedir();
@@ -193,4 +193,9 @@ public class SvnKitEnvironmentRepository extends AbstractScmEnvironmentRepositor
return svnPath;
}
@Override
public void setOrder(int order) {
super.setOrder(order);
}
}

View File

@@ -34,6 +34,7 @@ import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.core.Ordered;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
@@ -55,7 +56,9 @@ import static org.springframework.cloud.config.client.ConfigClientProperties.TOK
* @author Mark Paluch
*/
@ConfigurationProperties("spring.cloud.config.server.vault")
public class VaultEnvironmentRepository implements EnvironmentRepository, InitializingBean {
public class VaultEnvironmentRepository implements EnvironmentRepository, InitializingBean, Ordered {
public static final String VAULT_TOKEN = "X-Vault-Token";
/** Vault host. Defaults to 127.0.0.1. */
@NotEmpty
@@ -79,6 +82,8 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Initia
@NotEmpty
private String profileSeparator = ",";
private int order = Ordered.LOWEST_PRECEDENCE;
private RestTemplate rest;
//TODO: move to watchState:String on findOne?
@@ -227,6 +232,15 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Initia
this.profileSeparator = profileSeparator;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return order;
}
@JsonIgnoreProperties(ignoreUnknown = true)
static class VaultResponse extends VaultResponseSupport<JsonNode> {
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2013-2016 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
*
* http://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;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* @author Ryan Baxter
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ConfigServerApplication.class,
properties = { "spring.config.name:compositeconfigserver",
"spring.cloud.config.server.svn.uri:file:///./target/repos/svn-config-repo",
"spring.cloud.config.server.svn.order:2",
"spring.cloud.config.server.git.uri:file:./target/repos/config-repo",
"spring.cloud.config.server.git.order:1"},
webEnvironment = RANDOM_PORT)
@ActiveProfiles({ "test", "git", "subversion" })
public class CompositeConfigServerIntegrationTests {
@LocalServerPort
private int port;
@BeforeClass
public static void init() throws Exception {
ConfigServerTestUtils.prepareLocalRepo();
ConfigServerTestUtils.prepareLocalSvnRepo("src/test/resources/svn-config-repo",
"target/repos/svn-config-repo");
}
@Test
public void contextLoads() {
Environment environment = new TestRestTemplate().getForObject("http://localhost:"
+ port + "/foo/development/", Environment.class);
assertEquals(3, environment.getPropertySources().size());
assertEquals("overrides", environment.getPropertySources().get(0).getName());
assertTrue(environment.getPropertySources().get(1).getName().contains("config-repo") &&
!environment.getPropertySources().get(1).getName().contains("svn-config-repo"));
assertTrue(environment.getPropertySources().get(2).getName().contains("svn-config-repo"));
assertEquals("{spring.cloud.config.enabled=true}", environment
.getPropertySources().get(0).getSource().toString());
}
@Test
public void resourseEndpointsWork() {
//This request will get the file from the Git Repo
String text = new TestRestTemplate().getForObject("http://localhost:"
+ port + "/foo/development/composite/bar.properties", String.class);
String expected = "foo: bar";
assertEquals("invalid content", expected, text);
//This request will get the file from the SVN Repo
text = new TestRestTemplate().getForObject("http://localhost:"
+ port + "/foo/development/composite/bar.properties", String.class);
assertEquals("invalid content", expected, text);
}
}

View File

@@ -49,10 +49,4 @@ public class NativeConfigServerIntegrationTests {
+ port + "/bad/default/", String.class);
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
}
public static void main(String[] args) {
new SpringApplicationBuilder(ConfigServerApplication.class).profiles("native").properties(
"spring.config.name=configserver").run(args);
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2013-2016 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
*
* http://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.config;
import java.util.HashMap;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Ryan Baxter
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = CustomCompositeEnvironmentRepositoryTests.TestApplication.class, properties = {
"spring.config.name:compositeconfigserver", "spring.cloud.config.server.git.uri:file:./target/repos/config-repo",
"spring.cloud.config.server.git.order:1" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles({"test", "git"})
@DirtiesContext
public class CustomCompositeEnvironmentRepositoryTests {
@LocalServerPort
private int port;
@BeforeClass
public static void init() throws Exception {
ConfigServerTestUtils.prepareLocalRepo();
}
@Test
public void contextLoads() {
Environment environment = new TestRestTemplate().getForObject(
"http://localhost:" + port + "/foo/development/", Environment.class);
List<PropertySource> propertySources = environment.getPropertySources();
assertEquals(3, propertySources.size());
assertEquals("overrides", propertySources.get(0).getName());
assertTrue(propertySources.get(1).getName().contains("config-repo"));
assertEquals("p", propertySources.get(2).getName());
}
@Configuration
@EnableAutoConfiguration
@EnableConfigServer
protected static class TestApplication {
@Bean
public EnvironmentRepository environmentRepository() {
return new CustomEnvironmentRepository();
}
public static void main(String[] args) throws Exception {
SpringApplication.run(CustomEnvironmentRepositoryTests.TestApplication.class,
args);
}
}
static class CustomEnvironmentRepository implements EnvironmentRepository, Ordered {
@Override
public Environment findOne(String application, String profile, String label) {
Environment e = new Environment("test", new String[0], "label", "version",
"state");
PropertySource p = new PropertySource("p", new HashMap<>());
e.add(p);
return e;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright 2013-2016 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
*
* http://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.ArrayList;
import java.util.List;
import org.junit.Test;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.core.Ordered;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
* @author Ryan Baxter
*/
public class CompositeEnvironmentRepositoryTests {
private class TestOrderedEnvironmentRepository implements EnvironmentRepository, SearchPathLocator, Ordered {
private Environment env;
private Locations locations;
private int order = Ordered.LOWEST_PRECEDENCE;
public TestOrderedEnvironmentRepository(int order, Environment env, Locations locations) {
this.order = order;
this.env = env;
this.locations = locations;
}
@Override
public Environment findOne(String application, String profile, String label) {
return env;
}
@Override
public Locations getLocations(String application, String profile, String label) {
return locations;
}
@Override
public int getOrder() {
return order;
}
}
@Test
public void testOrder() {
PropertySource p1 = mock(PropertySource.class);
doReturn("p1").when(p1).getName();
PropertySource p2 = mock(PropertySource.class);
doReturn("p2").when(p2).getName();
PropertySource p3 = mock(PropertySource.class);
doReturn("p3").when(p3).getName();
PropertySource p4 = mock(PropertySource.class);
doReturn("p4").when(p4).getName();
PropertySource p5 = mock(PropertySource.class);
doReturn("p5").when(p5).getName();
String sLoc1 = "loc1";
String sLoc2 = "loc2";
String sLoc3 = "loc3";
String sLoc4 = "loc4";
String sLoc5 = "loc5";
Environment e1 = new Environment("app", "dev");
e1.add(p1);
e1.add(p5);
Environment e2 = new Environment("app", "dev");
e2.add(p2);
Environment e3 = new Environment("app", "dev");
e3.add(p3);
e3.add(p4);
SearchPathLocator.Locations loc1 = new SearchPathLocator.Locations("app", "dev", "label", "version", new String[]{sLoc1});
SearchPathLocator.Locations loc2 = new SearchPathLocator.Locations("app", "dev", "label", "version", new String[]{sLoc5, sLoc4});
SearchPathLocator.Locations loc3 = new SearchPathLocator.Locations("app", "dev", "label", "version", new String[]{sLoc3, sLoc2});
List<EnvironmentRepository> repos = new ArrayList<EnvironmentRepository>();
repos.add(new TestOrderedEnvironmentRepository(3, e1, loc1));
repos.add(new TestOrderedEnvironmentRepository(2, e3, loc2));
repos.add(new TestOrderedEnvironmentRepository(1, e2, loc3));
SearchPathCompositeEnvironmentRepository compositeRepo = new SearchPathCompositeEnvironmentRepository(repos);
Environment compositeEnv = compositeRepo.findOne("foo", "bar", "world");
List<PropertySource> propertySources = compositeEnv.getPropertySources();
assertEquals(5, propertySources.size());
assertEquals("p2", propertySources.get(0).getName());
assertEquals("p3", propertySources.get(1).getName());
assertEquals("p4", propertySources.get(2).getName());
assertEquals("p1", propertySources.get(3).getName());
assertEquals("p5", propertySources.get(4).getName());
SearchPathLocator.Locations locations = compositeRepo.getLocations("app", "dev", "label");
String[] locationStrings = locations.getLocations();
assertEquals(5, locationStrings.length);
assertEquals(sLoc3, locationStrings[0]);
assertEquals(sLoc2, locationStrings[1]);
assertEquals(sLoc5, locationStrings[2]);
assertEquals(sLoc4, locationStrings[3]);
assertEquals(sLoc1, locationStrings[4]);
}
}

View File

@@ -273,7 +273,7 @@ public class JGitEnvironmentRepositoryIntegrationTests {
.run("--spring.cloud.config.server.git.uri=" + uri,
"--spring.cloud.config.server.git.cloneOnStart=true");
EnvironmentRepository repository = this.context
.getBean(EnvironmentRepository.class);
.getBean(JGitEnvironmentRepository.class);
assertTrue(((JGitEnvironmentRepository) repository).isCloneOnStart());
Environment environment = repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());

View File

@@ -0,0 +1,9 @@
spring:
cloud:
config:
server:
overrides:
spring:
cloud:
config:
enabled: true

View File

@@ -1 +1,5 @@
0000000000000000000000000000000000000000 7df4a26d5437d9d4090cd5809967f870444cde8f Dave Syer <dsyer@gopivotal.com> 1406860717 -0700
7df4a26d5437d9d4090cd5809967f870444cde8f 9f01fb972bc9617e4ea59f5c8ee3ceb5ff515cd0 Ryan Baxter <rbaxter@pivotal.io> 1481905383 -0500 checkout: moving from raw to master
9f01fb972bc9617e4ea59f5c8ee3ceb5ff515cd0 7df4a26d5437d9d4090cd5809967f870444cde8f Ryan Baxter <rbaxter@pivotal.io> 1481905407 -0500 checkout: moving from master to raw
7df4a26d5437d9d4090cd5809967f870444cde8f 7df4a26d5437d9d4090cd5809967f870444cde8f Ryan Baxter <rbaxter@pivotal.io> 1481905544 -0500 checkout: moving from raw to composite
7df4a26d5437d9d4090cd5809967f870444cde8f 7df4a26d5437d9d4090cd5809967f870444cde8f Ryan Baxter <rbaxter@pivotal.io> 1481905552 -0500 checkout: moving from composite to raw

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 7df4a26d5437d9d4090cd5809967f870444cde8f Ryan Baxter <rbaxter@pivotal.io> 1481905474 -0500 branch: Created from raw

View File

@@ -0,0 +1 @@
7df4a26d5437d9d4090cd5809967f870444cde8f

View File

@@ -0,0 +1,13 @@
K 10
svn:author
V 11
ryanjbaxter
K 8
svn:date
V 27
2016-12-16T16:51:59.468533Z
K 7
svn:log
V 23
adding composite branch
END

View File

@@ -0,0 +1,9 @@
id: 0.0.t2-4
type: dir
pred: 0.0.r2/1211
count: 3
text: 2 1126 72 0 a8927d430ec09518c534d157c6e49580
cpath: /
copyroot: 0 /
is-fresh-txn-root: y