Allows users to provide composite environments. Fixes #495.

This commit is contained in:
Ryan Baxter
2016-12-19 12:28:41 -05:00
parent 5eccc4ae45
commit 133c172ddd
31 changed files with 645 additions and 26 deletions

View File

@@ -556,6 +556,58 @@ $ 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 `OrderedEnvironmentRepository`. For convenience sake, there is
an abstract implementation of this interface you can extend called
`AbstractOrderedEnvironmentRepository`. If you extend `AbstractOrderedEnvironmentRepository`
your environment repository will have the lowest possible precedence by default.
If you would like to change this, make sure you call the `setOrder` method
to set the precedence or override the `getOrder` method to return the order
value you would like your environment repository to have.
==== 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 add(List<PropertySource> propertySources) {
this.propertySources.addAll(propertySources);
}
public void addFirst(PropertySource propertySource) {
this.propertySources.add(0, propertySource);
}

View File

@@ -0,0 +1,59 @@
/*
* 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.OrderedEnvironmentRepository;
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
@ConditionalOnBean(OrderedEnvironmentRepository.class)
public class CompositeConfiguration {
private List<OrderedEnvironmentRepository> environmentRepos = new ArrayList<>();
@Bean
@Primary
@ConditionalOnBean(SearchPathLocator.class)
public SearchPathCompositeEnvironmentRepository compositeEnvironmentRepository() {
return new SearchPathCompositeEnvironmentRepository(environmentRepos);
}
@Bean
@Primary
@ConditionalOnMissingBean(SearchPathLocator.class)
public CompositeEnvironmentRepository compositeEnvironmentRepository2() {
return new CompositeEnvironmentRepository(environmentRepos);
}
@Autowired
private void setEnvironmentRepos(List<OrderedEnvironmentRepository> 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
@@ -56,15 +55,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 {
protected static class DefaultRepositoryConfiguration {
@Autowired
private ConfigurableEnvironment environment;
@@ -73,7 +71,7 @@ public class EnvironmentRepositoryConfiguration {
private ConfigServerProperties server;
@Bean
public MultipleJGitEnvironmentRepository environmentRepository() {
public MultipleJGitEnvironmentRepository defaultEnvironmentRepository() {
MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment);
if (this.server.getDefaultLabel()!=null) {
repository.setDefaultLabel(this.server.getDefaultLabel());
@@ -82,6 +80,10 @@ public class EnvironmentRepositoryConfiguration {
}
}
@Configuration
@Profile("git")
protected static class GitRepositoryConfiguration extends DefaultRepositoryConfiguration {}
@Configuration
@Profile("subversion")
protected static class SvnRepositoryConfiguration {
@@ -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

@@ -0,0 +1,34 @@
/*
* 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 org.springframework.core.Ordered;
/**
* @author Ryan Baxter
*/
public abstract class AbstractOrderedEnvironmentRepository implements OrderedEnvironmentRepository {
private int order = Ordered.LOWEST_PRECEDENCE;
@Override
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}

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 OrderedEnvironmentRepository, SearchPathLocator {
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 OrderedEnvironmentRepository}s.
* @author Ryan Baxter
*/
public class CompositeEnvironmentRepository implements EnvironmentRepository {
protected List<OrderedEnvironmentRepository> environmentRepositories;
/**
* Creates a new {@link CompositeEnvironmentRepository}.
* @param environmentRepositories The list of {@link OrderedEnvironmentRepository}s to create the composite from.
*/
public CompositeEnvironmentRepository(List<OrderedEnvironmentRepository> 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.add(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

@@ -47,8 +47,8 @@ import org.springframework.util.StringUtils;
* @author Roy Clarkson
*/
@ConfigurationProperties("spring.cloud.config.server.native")
public class NativeEnvironmentRepository
implements EnvironmentRepository, SearchPathLocator {
public class NativeEnvironmentRepository extends AbstractOrderedEnvironmentRepository
implements SearchPathLocator {
private static Log logger = LogFactory.getLog(NativeEnvironmentRepository.class);

View File

@@ -0,0 +1,25 @@
/*
* 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 org.springframework.core.Ordered;
/**
* A prioritized {@link EnvironmentRepository}.
* @author Ryan Baxter
*/
public interface OrderedEnvironmentRepository extends EnvironmentRepository, Ordered {
}

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 OrderedEnvironmentRepository}s to create this composite from.
*/
public SearchPathCompositeEnvironmentRepository(List<OrderedEnvironmentRepository> 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

@@ -35,7 +35,7 @@ import static org.springframework.cloud.config.client.ConfigClientProperties.TOK
* @author Spencer Gibb
*/
@ConfigurationProperties("spring.cloud.config.server.vault")
public class VaultEnvironmentRepository implements EnvironmentRepository {
public class VaultEnvironmentRepository extends AbstractOrderedEnvironmentRepository {
public static final String VAULT_TOKEN = "X-Vault-Token";
@@ -190,6 +190,11 @@ public class VaultEnvironmentRepository implements EnvironmentRepository {
this.profileSeparator = profileSeparator;
}
@Override
public void setOrder(int order) {
super.setOrder(order);
}
static class VaultResponse {
private String auth;

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,100 @@
/*
* 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.AbstractOrderedEnvironmentRepository;
import org.springframework.cloud.config.server.environment.OrderedEnvironmentRepository;
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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 OrderedEnvironmentRepository environmentRepository() {
return new AbstractOrderedEnvironmentRepository() {
@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;
}
};
}
public static void main(String[] args) throws Exception {
SpringApplication.run(CustomEnvironmentRepositoryTests.TestApplication.class,
args);
}
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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 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 extends AbstractOrderedEnvironmentRepository implements SearchPathLocator {
private Environment env;
private Locations locations;
public TestOrderedEnvironmentRepository(int order, Environment env, Locations locations) {
setOrder(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;
}
}
@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<OrderedEnvironmentRepository> repos = new ArrayList<OrderedEnvironmentRepository>();
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