Merge branch 'master' into 2.0.x

# Conflicts:
#	docs/pom.xml
#	pom.xml
#	spring-cloud-config-client/pom.xml
#	spring-cloud-config-dependencies/pom.xml
#	spring-cloud-config-monitor/pom.xml
#	spring-cloud-config-sample/pom.xml
#	spring-cloud-config-server/pom.xml
#	spring-cloud-starter-config/pom.xml
This commit is contained in:
Spencer Gibb
2017-04-28 15:58:33 -06:00
29 changed files with 707 additions and 181 deletions

View File

@@ -594,7 +594,7 @@ Properties written to `secret/application` are available to
<<_vault_server,all applications using the Config Server>>. An
application with the name `myApp` would have any properties
written to `secret/myApp` and `secret/application` available to it.
When `myApp` has the `dev` profile enabled than properties written to
When `myApp` has the `dev` profile enabled then properties written to
all of the above paths would be available to it, with properties in
the first path in the list taking priority over the others.
@@ -680,7 +680,7 @@ using one of the environment repositories from Spring Cloud. To do this your be
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
`getOrdered` method. If you do not implement the `Ordered` interface then your
`EnvironmentRepository` will be given the lowest priority.
==== Property Overrides

10
mvnw vendored
View File

@@ -238,8 +238,16 @@ else
echo $MAVEN_ARGS | grep -q milestone && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pmilestone//')
fi
if echo $VERSION | egrep -q 'RELEASE'; then
echo Activating \"central\" profile for version=\"$VERSION\"
echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pcentral"
else
echo Deactivating \"central\" profile for version=\"$VERSION\"
echo $MAVEN_ARGS | grep -q central && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pcentral//')
fi
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} ${MAVEN_ARGS} "$@"
${WRAPPER_LAUNCHER} ${MAVEN_ARGS} "$@"

View File

@@ -49,6 +49,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<type>test-jar</type>
<scope>test</scope>
<version>${spring-cloud-commons.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<profiles>

View File

@@ -76,6 +76,12 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -18,10 +18,13 @@ package org.springframework.cloud.config.client;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
@@ -95,6 +98,11 @@ public class ConfigClientProperties {
*/
private String authorization;
/**
* Additional headers used to create the client request.
*/
private Map<String, String> headers = new HashMap<>();
private ConfigClientProperties() {
}
@@ -190,6 +198,8 @@ public class ConfigClientProperties {
this.token = token;
}
@DeprecatedConfigurationProperty(reason = "replaced by headers", replacement = "headers")
@Deprecated
public String getAuthorization() {
return this.authorization;
}
@@ -198,6 +208,14 @@ public class ConfigClientProperties {
this.authorization = authorization;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
private Credentials extractCredentials() {
Credentials result = new Credentials();
String uri = this.uri;

View File

@@ -0,0 +1,33 @@
package org.springframework.cloud.config.client;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.retry.annotation.Retryable;
import java.util.List;
public class ConfigServerInstanceProvider {
private static Log logger = LogFactory.getLog(ConfigServerInstanceProvider.class);
private final DiscoveryClient client;
public ConfigServerInstanceProvider(DiscoveryClient client) {
this.client = client;
}
@Retryable(interceptor = "configServerRetryInterceptor")
public ServiceInstance getConfigServerInstance(String serviceId) {
logger.debug("Locating configserver (" + serviceId + ") via discovery");
List<ServiceInstance> instances = this.client.getInstances(serviceId);
if (instances.isEmpty()) {
throw new IllegalStateException(
"No instances found of configserver (" + serviceId + ")");
}
ServiceInstance instance = instances.get(0);
logger.debug(
"Located configserver (" + serviceId + ") via discovery: " + instance);
return instance;
}
}

View File

@@ -20,6 +20,7 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -52,6 +53,7 @@ import static org.springframework.cloud.config.client.ConfigClientProperties.TOK
/**
* @author Dave Syer
* @author Mathieu Ouellet
*
*/
@Order(0)
@@ -191,8 +193,10 @@ public class ConfigServicePropertySourceLocator implements PropertySourceLocator
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setReadTimeout((60 * 1000 * 3) + 5000); //TODO 3m5s, make configurable?
RestTemplate template = new RestTemplate(requestFactory);
String username = client.getUsername();
String password = client.getPassword();
String authorization = client.getAuthorization();
Map<String, String> headers = new HashMap<>(client.getHeaders());
if (password != null && authorization != null) {
throw new IllegalStateException(
@@ -200,53 +204,36 @@ public class ConfigServicePropertySourceLocator implements PropertySourceLocator
}
if (password != null) {
template.setInterceptors(Arrays.<ClientHttpRequestInterceptor> asList(
new BasicAuthorizationInterceptor(client.getUsername(), password)));
byte[] token = Base64Utils.encode((username + ":" + password).getBytes());
headers.put("Authorization", "Basic " + new String(token));
}
else if (authorization != null) {
headers.put("Authorization", authorization);
}
if (!headers.isEmpty()) {
template.setInterceptors(Arrays.<ClientHttpRequestInterceptor> asList(
new GenericAuthorization(authorization)));
new GenericRequestHeaderInterceptor(headers)));
}
return template;
}
private static class BasicAuthorizationInterceptor implements
ClientHttpRequestInterceptor {
public static class GenericRequestHeaderInterceptor
implements ClientHttpRequestInterceptor {
private final String username;
private final Map<String, String> headers;
private final String password;
public BasicAuthorizationInterceptor(String username, String password) {
this.username = username;
this.password = (password == null ? "" : password);
public GenericRequestHeaderInterceptor(Map<String, String> headers) {
this.headers = headers;
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
byte[] token = Base64Utils.encode((this.username + ":" + this.password).getBytes());
request.getHeaders().add("Authorization", "Basic " + new String(token));
return execution.execute(request, body);
}
}
private static class GenericAuthorization implements
ClientHttpRequestInterceptor {
private final String authorizationToken;
public GenericAuthorization(String authorizationToken) {
this.authorizationToken = (authorizationToken == null ? "" : authorizationToken);
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
request.getHeaders().add("Authorization", authorizationToken);
for (Entry<String, String> header : headers.entrySet()) {
request.getHeaders().add(header.getKey(), header.getValue());
}
return execution.execute(request, body);
}
}

View File

@@ -16,8 +16,6 @@
package org.springframework.cloud.config.client;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,6 +26,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.cloud.client.discovery.event.HeartbeatMonitor;
import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.ContextRefreshedEvent;
@@ -52,10 +51,16 @@ public class DiscoveryClientConfigServiceBootstrapConfiguration {
private ConfigClientProperties config;
@Autowired
private DiscoveryClient client;
private ConfigServerInstanceProvider instanceProvider;
private HeartbeatMonitor monitor = new HeartbeatMonitor();
@Bean
public ConfigServerInstanceProvider configServerInstanceProvider(
DiscoveryClient discoveryClient) {
return new ConfigServerInstanceProvider(discoveryClient);
}
@EventListener(ContextRefreshedEvent.class)
public void startup(ContextRefreshedEvent event) {
refresh();
@@ -70,14 +75,9 @@ public class DiscoveryClientConfigServiceBootstrapConfiguration {
private void refresh() {
try {
logger.debug("Locating configserver via discovery");
String serviceId = this.config.getDiscovery().getServiceId();
List<ServiceInstance> instances = this.client.getInstances(serviceId);
if (instances.isEmpty()) {
logger.warn("No instances found of configserver (" + serviceId + ")");
return;
}
ServiceInstance server = instances.get(0);
ServiceInstance server = this.instanceProvider
.getConfigServerInstance(serviceId);
String url = getHomePage(server);
if (server.getMetadata().containsKey("password")) {
String user = server.getMetadata().get("user");
@@ -96,7 +96,12 @@ public class DiscoveryClientConfigServiceBootstrapConfiguration {
this.config.setUri(url);
}
catch (Exception ex) {
logger.warn("Could not locate configserver via discovery", ex);
if (config.isFailFast()) {
throw ex;
}
else {
logger.warn("Could not locate configserver via discovery", ex);
}
}
}

View File

@@ -0,0 +1,106 @@
package org.springframework.cloud.config.client;
import org.junit.After;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
import java.util.Collections;
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.springframework.cloud.config.client.ConfigClientProperties.Discovery.DEFAULT_CONFIG_SERVER;
public abstract class BaseDiscoveryClientConfigServiceBootstrapConfigurationTests {
@Rule
public ExpectedException expectedException = ExpectedException.none();
protected AnnotationConfigApplicationContext context;
protected DiscoveryClient client = Mockito.mock(DiscoveryClient.class);
protected ServiceInstance info = new DefaultServiceInstance("app", "foo", 8877,
false);
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
void givenDiscoveryClientReturnsNoInfo() {
given(this.client.getInstances(DEFAULT_CONFIG_SERVER))
.willReturn(Collections.<ServiceInstance> emptyList());
}
void givenDiscoveryClientReturnsInfo() {
given(this.client.getInstances(DEFAULT_CONFIG_SERVER))
.willReturn(Arrays.asList(this.info));
}
void givenDiscoveryClientReturnsInfoOnThirdTry() {
given(this.client.getInstances(DEFAULT_CONFIG_SERVER))
.willReturn(Collections.<ServiceInstance> emptyList())
.willReturn(Collections.<ServiceInstance> emptyList())
.willReturn(Arrays.asList(this.info));
}
void expectNoInstancesOfConfigServerException() {
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage(
"No instances found of configserver (" + DEFAULT_CONFIG_SERVER + ")");
}
void expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup() {
assertEquals(1, this.context.getBeanNamesForType(
DiscoveryClientConfigServiceBootstrapConfiguration.class).length);
}
void expectConfigClientPropertiesHasDefaultConfiguration() {
expectConfigClientPropertiesHasConfiguration("http://localhost:8888");
}
void expectConfigClientPropertiesHasConfigurationFromEureka() {
expectConfigClientPropertiesHasConfiguration("http://foo:8877/");
}
void expectConfigClientPropertiesHasConfiguration(final String expectedUri) {
ConfigClientProperties properties = this.context
.getBean(ConfigClientProperties.class);
assertEquals(expectedUri, properties.getRawUri());
}
void verifyDiscoveryClientCalledThreeTimes() {
verify(this.client, times(3)).getInstances(DEFAULT_CONFIG_SERVER);
}
void verifyDiscoveryClientCalledOnce() {
verify(this.client).getInstances(DEFAULT_CONFIG_SERVER);
}
void setup(String... env) {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, env);
EnvironmentTestUtils.addEnvironment(this.context, "eureka.client.enabled=false");
this.context.getDefaultListableBeanFactory().registerSingleton("discoveryClient",
this.client);
this.context.register(UtilAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
DiscoveryClientConfigServiceBootstrapConfiguration.class,
ConfigServiceBootstrapConfiguration.class, ConfigClientProperties.class);
this.context.refresh();
}
}

View File

@@ -1,10 +1,13 @@
package org.springframework.cloud.config.client;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import org.hamcrest.core.IsInstanceOf;
import org.hamcrest.core.IsNull;
@@ -24,8 +27,11 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.mock.http.client.MockClientHttpRequest;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
@@ -103,7 +109,7 @@ public class ConfigServicePropertySourceLocatorTests {
this.expected.expectCause(IsInstanceOf
.<Throwable> instanceOf(HttpServerErrorException.class));
this.expected.expectMessage("fail fast property is set");
assertNull(this.locator.locate(this.environment));
this.locator.locate(this.environment);
}
@Test
@@ -131,7 +137,85 @@ public class ConfigServicePropertySourceLocatorTests {
this.locator.setRestTemplate(restTemplate);
this.expected.expectCause(IsNull.nullValue(Throwable.class));
this.expected.expectMessage("fail fast property is set");
assertNull(this.locator.locate(this.environment));
this.locator.locate(this.environment);
}
@Test
public void failFastWhenBothPasswordAndAuthorizationPropertiesSet() throws Exception {
ClientHttpRequestFactory requestFactory = Mockito
.mock(ClientHttpRequestFactory.class);
ClientHttpRequest request = Mockito.mock(ClientHttpRequest.class);
Mockito.when(
requestFactory.createRequest(Mockito.any(URI.class),
Mockito.any(HttpMethod.class))).thenReturn(request);
ConfigClientProperties defaults = new ConfigClientProperties(this.environment);
defaults.setFailFast(true);
defaults.setUsername("username");
defaults.setPassword("password");
defaults.setAuthorization("Basic dXNlcm5hbWU6cGFzc3dvcmQNCg==");
this.locator = new ConfigServicePropertySourceLocator(defaults);
this.expected.expect(IllegalStateException.class);
this.expected.expectMessage("You must set either 'password' or 'authorization'");
this.locator.locate(this.environment);
}
@Test
public void interceptorShouldAddHeaderWhenPasswordPropertySet() throws Exception {
ClientHttpRequestFactory requestFactory = Mockito
.mock(ClientHttpRequestFactory.class);
ClientHttpRequest request = Mockito.mock(ClientHttpRequest.class);
Mockito.when(requestFactory.createRequest(Mockito.any(URI.class),
Mockito.any(HttpMethod.class))).thenReturn(request);
ConfigClientProperties defaults = new ConfigClientProperties(this.environment);
defaults.setUsername("username");
defaults.setPassword("password");
this.locator = new ConfigServicePropertySourceLocator(defaults);
RestTemplate restTemplate = ReflectionTestUtils.invokeMethod(this.locator,
"getSecureRestTemplate", defaults);
restTemplate.setRequestFactory(requestFactory);
this.locator.setRestTemplate(restTemplate);
this.locator.locate(this.environment);
assertThat(restTemplate.getInterceptors()).hasSize(1);
}
@Test
public void interceptorShouldAddHeaderWhenAuthorizationPropertySet() throws Exception {
ClientHttpRequestFactory requestFactory = Mockito
.mock(ClientHttpRequestFactory.class);
ClientHttpRequest request = Mockito.mock(ClientHttpRequest.class);
Mockito.when(requestFactory.createRequest(Mockito.any(URI.class),
Mockito.any(HttpMethod.class))).thenReturn(request);
ConfigClientProperties defaults = new ConfigClientProperties(this.environment);
defaults.setAuthorization("Basic dXNlcm5hbWU6cGFzc3dvcmQ=");
this.locator = new ConfigServicePropertySourceLocator(defaults);
RestTemplate restTemplate = ReflectionTestUtils.invokeMethod(this.locator,
"getSecureRestTemplate", defaults);
restTemplate.setRequestFactory(requestFactory);
this.locator.setRestTemplate(restTemplate);
this.locator.locate(this.environment);
assertThat(restTemplate.getInterceptors()).hasSize(1);
}
@Test
public void interceptorShouldAddHeadersWhenHeadersPropertySet() throws Exception {
MockClientHttpRequest request = new MockClientHttpRequest();
ClientHttpRequestExecution execution = Mockito
.mock(ClientHttpRequestExecution.class);
byte[] body = new byte[] {};
Map<String, String> headers = new HashMap<>();
headers.put("X-Example-Version", "2.1");
new ConfigServicePropertySourceLocator.GenericRequestHeaderInterceptor(headers)
.intercept(request, body, execution);
Mockito.verify(execution).execute(request, body);
assertThat(request.getHeaders().getFirst("X-Example-Version")).isEqualTo("2.1");
}
@SuppressWarnings("unchecked")

View File

@@ -0,0 +1,50 @@
package org.springframework.cloud.config.client;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.cloud.ClassPathExclusions;
import org.springframework.cloud.FilteredClassPathRunner;
@RunWith(FilteredClassPathRunner.class)
@ClassPathExclusions({ "spring-retry-*.jar", "spring-boot-starter-aop-*.jar" })
public class DiscoveryClientConfigServiceBootstrapConfigurationNoSpringRetryTests
extends BaseDiscoveryClientConfigServiceBootstrapConfigurationTests {
@Test
public void shouldFailWithExceptionGetConfigServerInstanceFromDiscoveryClient()
throws Exception {
givenDiscoveryClientReturnsNoInfo();
expectNoInstancesOfConfigServerException();
setup("spring.cloud.config.discovery.enabled=true",
"spring.cloud.config.failFast=true");
}
@Test
public void shouldFailWithMessageGetConfigServerInstanceFromDiscoveryClient()
throws Exception {
givenDiscoveryClientReturnsNoInfo();
setup("spring.cloud.config.discovery.enabled=true",
"spring.cloud.config.failFast=false");
expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
expectConfigClientPropertiesHasDefaultConfiguration();
verifyDiscoveryClientCalledOnce();
}
@Test
public void shouldSucceedGetConfigServerInstanceFromDiscoveryClient()
throws Exception {
givenDiscoveryClientReturnsInfo();
setup("spring.cloud.config.discovery.enabled=true",
"spring.cloud.config.failFast=true");
expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
expectConfigClientPropertiesHasConfigurationFromEureka();
verifyDiscoveryClientCalledOnce();
}
}

View File

@@ -16,46 +16,24 @@
package org.springframework.cloud.config.client;
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.springframework.cloud.config.client.ConfigClientProperties.Discovery.DEFAULT_CONFIG_SERVER;
import java.util.Arrays;
import org.junit.After;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.assertEquals;
/**
* @author Dave Syer
*/
public class DiscoveryClientConfigServiceBootstrapConfigurationTests {
private AnnotationConfigApplicationContext context;
private DiscoveryClient client = Mockito.mock(DiscoveryClient.class);
private ServiceInstance info = new DefaultServiceInstance("app", "foo", 8877, false);
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
public class DiscoveryClientConfigServiceBootstrapConfigurationTests extends BaseDiscoveryClientConfigServiceBootstrapConfigurationTests {
@Test
public void offByDefault() throws Exception {
this.context = new AnnotationConfigApplicationContext(
DiscoveryClientConfigServiceBootstrapConfiguration.class);
assertEquals(0, this.context.getBeanNamesForType(DiscoveryClient.class).length);
assertEquals(0, this.context.getBeanNamesForType(
DiscoveryClientConfigServiceBootstrapConfiguration.class).length);
@@ -63,51 +41,49 @@ public class DiscoveryClientConfigServiceBootstrapConfigurationTests {
@Test
public void onWhenRequested() throws Exception {
given(this.client.getInstances(DEFAULT_CONFIG_SERVER))
.willReturn(Arrays.asList(this.info));
givenDiscoveryClientReturnsInfo();
setup("spring.cloud.config.discovery.enabled=true");
assertEquals(1, this.context.getBeanNamesForType(
DiscoveryClientConfigServiceBootstrapConfiguration.class).length);
Mockito.verify(this.client).getInstances(DEFAULT_CONFIG_SERVER);
ConfigClientProperties locator = this.context
.getBean(ConfigClientProperties.class);
assertEquals("http://foo:8877/", locator.getRawUri());
expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
verifyDiscoveryClientCalledOnce();
expectConfigClientPropertiesHasConfigurationFromEureka();
}
@Test
public void onWhenHeartbeat() throws Exception {
setup("spring.cloud.config.discovery.enabled=true");
assertEquals(1, this.context.getBeanNamesForType(
DiscoveryClientConfigServiceBootstrapConfiguration.class).length);
given(this.client.getInstances(DEFAULT_CONFIG_SERVER))
.willReturn(Arrays.asList(this.info));
Mockito.verify(this.client).getInstances(DEFAULT_CONFIG_SERVER);
expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
givenDiscoveryClientReturnsInfo();
verifyDiscoveryClientCalledOnce();
context.publishEvent(new HeartbeatEvent(context, "new"));
ConfigClientProperties locator = this.context
.getBean(ConfigClientProperties.class);
assertEquals("http://foo:8877/", locator.getRawUri());
expectConfigClientPropertiesHasConfigurationFromEureka();
}
@Test
public void secureWhenRequested() throws Exception {
this.info = new DefaultServiceInstance("app", "foo", 443, true);
given(this.client.getInstances(DEFAULT_CONFIG_SERVER))
.willReturn(Arrays.asList(this.info));
givenDiscoveryClientReturnsInfo();
setup("spring.cloud.config.discovery.enabled=true");
assertEquals(1, this.context.getBeanNamesForType(
DiscoveryClientConfigServiceBootstrapConfiguration.class).length);
Mockito.verify(this.client).getInstances(DEFAULT_CONFIG_SERVER);
ConfigClientProperties locator = this.context
.getBean(ConfigClientProperties.class);
assertEquals("https://foo:443/", locator.getRawUri());
expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
verifyDiscoveryClientCalledOnce();
expectConfigClientPropertiesHasConfiguration("https://foo:443/");
}
@Test
public void setsPasssword() throws Exception {
this.info.getMetadata().put("password", "bar");
given(this.client.getInstances(DEFAULT_CONFIG_SERVER))
.willReturn(Arrays.asList(this.info));
givenDiscoveryClientReturnsInfo();
setup("spring.cloud.config.discovery.enabled=true");
ConfigClientProperties locator = this.context
.getBean(ConfigClientProperties.class);
assertEquals("http://foo:8877/", locator.getRawUri());
@@ -118,25 +94,80 @@ public class DiscoveryClientConfigServiceBootstrapConfigurationTests {
@Test
public void setsPath() throws Exception {
this.info.getMetadata().put("configPath", "/bar");
given(this.client.getInstances(DEFAULT_CONFIG_SERVER))
.willReturn(Arrays.asList(this.info));
givenDiscoveryClientReturnsInfo();
setup("spring.cloud.config.discovery.enabled=true");
ConfigClientProperties locator = this.context
.getBean(ConfigClientProperties.class);
assertEquals("http://foo:8877/bar", locator.getRawUri());
expectConfigClientPropertiesHasConfiguration("http://foo:8877/bar");
}
private void setup(String... env) {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, env);
EnvironmentTestUtils.addEnvironment(this.context, "eureka.client.enabled=false");
this.context.getDefaultListableBeanFactory().registerSingleton("discoveryClient",
this.client);
this.context.register(UtilAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
DiscoveryClientConfigServiceBootstrapConfiguration.class,
ConfigClientProperties.class);
this.context.refresh();
@Test
public void shouldFailGetConfigServerInstanceFromDiscoveryClient() throws Exception {
givenDiscoveryClientReturnsNoInfo();
setup("spring.cloud.config.discovery.enabled=true");
expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
verifyDiscoveryClientCalledOnce();
expectConfigClientPropertiesHasDefaultConfiguration();
}
@Test
public void shouldRetryAndSucceedGetConfigServerInstanceFromDiscoveryClient()
throws Exception {
givenDiscoveryClientReturnsInfoOnThirdTry();
setup("spring.cloud.config.discovery.enabled=true",
"spring.cloud.config.retry.maxAttempts=3",
"spring.cloud.config.retry.initialInterval=10",
"spring.cloud.config.failFast=true");
expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
verifyDiscoveryClientCalledThreeTimes();
context.publishEvent(new HeartbeatEvent(context, "new"));
expectConfigClientPropertiesHasConfigurationFromEureka();
}
@Test
public void shouldNotRetryIfNotFailFastPropertySet() throws Exception {
givenDiscoveryClientReturnsInfoOnThirdTry();
setup("spring.cloud.config.discovery.enabled=true",
"spring.cloud.config.retry.maxAttempts=3",
"spring.cloud.config.retry.initialInterval=10");
expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
verifyDiscoveryClientCalledOnce();
expectConfigClientPropertiesHasDefaultConfiguration();
}
@Test
public void shouldRetryAndFailWithExceptionGetConfigServerInstanceFromDiscoveryClient()
throws Exception {
givenDiscoveryClientReturnsNoInfo();
expectNoInstancesOfConfigServerException();
setup("spring.cloud.config.discovery.enabled=true",
"spring.cloud.config.retry.maxAttempts=3",
"spring.cloud.config.retry.initialInterval=10",
"spring.cloud.config.failFast=true");
}
@Test
public void shouldRetryAndFailWithMessageGetConfigServerInstanceFromDiscoveryClient()
throws Exception {
givenDiscoveryClientReturnsNoInfo();
setup("spring.cloud.config.discovery.enabled=true",
"spring.cloud.config.retry.maxAttempts=3",
"spring.cloud.config.retry.initialInterval=10",
"spring.cloud.config.failFast=false");
expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
expectConfigClientPropertiesHasDefaultConfiguration();
}
}

View File

@@ -13,7 +13,7 @@
<description>Spring Cloud Config Monitor</description>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
<spring-cloud-bus.version>1.3.0.BUILD-SNAPSHOT</spring-cloud-bus.version>
<spring-cloud-bus.version>1.3.1.BUILD-SNAPSHOT</spring-cloud-bus.version>
</properties>
<dependencyManagement>
<dependencies>

View File

@@ -3,7 +3,8 @@ package sample;
import org.junit.Test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class ApplicationFailFastTests {

View File

@@ -77,8 +77,13 @@ public class CipherEnvironmentEncryptor implements EnvironmentEncryptor {
catch (Exception e) {
value = "<n/a>";
name = "invalid." + name;
logger.warn("Cannot decrypt key: " + key + " (" + e.getClass()
+ ": " + e.getMessage() + ")");
String message = "Cannot decrypt key: " + key + " (" + e.getClass()
+ ": " + e.getMessage() + ")";
if (logger.isDebugEnabled()) {
logger.debug(message, e);
} else if (logger.isWarnEnabled()) {
logger.warn(message);
}
}
map.put(name, value);
}

View File

@@ -125,19 +125,14 @@ public class EncryptionController {
public String encrypt(@PathVariable String name, @PathVariable String profiles,
@RequestBody String data, @RequestHeader("Content-Type") MediaType type) {
checkEncryptorInstalled(name, profiles);
try {
String input = stripFormData(data, type, false);
Map<String, String> keys = this.helper.getEncryptorKeys(name, profiles,
input);
String textToEncrypt = this.helper.stripPrefix(input);
String encrypted = this.helper.addPrefix(keys,
this.encryptor.locate(keys).encrypt(textToEncrypt));
logger.info("Encrypted data");
return encrypted;
}
catch (IllegalArgumentException e) {
throw new InvalidCipherException();
}
String input = stripFormData(data, type, false);
Map<String, String> keys = this.helper.getEncryptorKeys(name, profiles,
input);
String textToEncrypt = this.helper.stripPrefix(input);
String encrypted = this.helper.addPrefix(keys,
this.encryptor.locate(keys).encrypt(textToEncrypt));
logger.info("Encrypted data");
return encrypted;
}
@RequestMapping(value = "decrypt", method = RequestMethod.POST)
@@ -161,7 +156,8 @@ public class EncryptionController {
logger.info("Decrypted cipher data");
return decrypted;
}
catch (IllegalArgumentException e) {
catch (IllegalArgumentException|IllegalStateException e) {
logger.error("Cannot decrypt key:" + name + ", value:" + data, e);
throw new InvalidCipherException();
}
}
@@ -241,4 +237,4 @@ class KeyNotAvailableException extends RuntimeException {
@SuppressWarnings("serial")
class InvalidCipherException extends RuntimeException {
}
}

View File

@@ -170,7 +170,7 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
/**
* Get the working directory ready.
*/
private String refresh(String label) {
public String refresh(String label) {
initialize();
Git git = null;
try {
@@ -197,7 +197,7 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
return git.getRepository().getRef("HEAD").getObjectId().getName();
}
catch (RefNotFoundException e) {
throw new NoSuchLabelException("No such label: " + label);
throw new NoSuchLabelException("No such label: " + label, e);
}
catch (GitAPIException e) {
throw new IllegalStateException("Cannot clone or checkout repository", e);
@@ -302,14 +302,15 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
setCredentialsProvider(fetch);
FetchResult result = fetch.call();
if(result.getTrackingRefUpdates() != null && result.getTrackingRefUpdates().size() > 0) {
this.logger.info("Fetched for remote " + label + " and found " + result.getTrackingRefUpdates().size()
logger.info("Fetched for remote " + label + " and found " + result.getTrackingRefUpdates().size()
+ " updates");
}
return result;
}
catch (Exception ex) {
this.logger.warn("Could not fetch remote for " + label + " remote: " + git
.getRepository().getConfig().getString("remote", "origin", "url"));
String message = "Could not fetch remote for " + label + " remote: " + git
.getRepository().getConfig().getString("remote", "origin", "url");
warn(message, ex);
return null;
}
}
@@ -325,8 +326,9 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
return result;
}
catch (Exception ex) {
this.logger.warn("Could not merge remote for " + label + " remote: " + git
.getRepository().getConfig().getString("remote", "origin", "url"));
String message = "Could not merge remote for " + label + " remote: " + git
.getRepository().getConfig().getString("remote", "origin", "url");
warn(message, ex);
return null;
}
}
@@ -343,9 +345,10 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
return resetRef;
}
catch (Exception ex) {
this.logger.warn("Could not reset to remote for " + label + " (current ref="
String message = "Could not reset to remote for " + label + " (current ref="
+ ref + "), remote: " + git.getRepository().getConfig()
.getString("remote", "origin", "url"));
.getString("remote", "origin", "url");
warn(message, ex);
return null;
}
}
@@ -449,10 +452,9 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
return status.call().isClean();
}
catch (Exception e) {
this.logger
.warn("Could not execute status command on local repository. Cause: ("
+ e.getClass().getSimpleName() + ") " + e.getMessage());
String message = "Could not execute status command on local repository. Cause: ("
+ e.getClass().getSimpleName() + ") " + e.getMessage();
warn(message, e);
return false;
}
}
@@ -486,6 +488,13 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
return false;
}
protected void warn(String message, Exception ex) {
logger.warn(message);
if (logger.isDebugEnabled()) {
logger.debug("Stacktrace for: " + message, ex);
}
}
/**
* Wraps the static method calls to {@link org.eclipse.jgit.api.Git} and
* {@link org.eclipse.jgit.api.CloneCommand} allowing for easier unit testing.

View File

@@ -119,7 +119,7 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
if (logger.isDebugEnabled()) {
this.logger.debug("Cannot retrieve resource locations from "
+ candidate.getUri() + ", cause: ("
+ e.getClass().getSimpleName() + ") " + e.getMessage());
+ e.getClass().getSimpleName() + ") " + e.getMessage(), e);
}
continue;
}
@@ -154,7 +154,7 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
if (logger.isDebugEnabled()) {
this.logger.debug("Cannot load configuration from "
+ candidate.getUri() + ", cause: ("
+ e.getClass().getSimpleName() + ") " + e.getMessage());
+ e.getClass().getSimpleName() + ") " + e.getMessage(), e);
}
continue;
}

View File

@@ -27,4 +27,8 @@ public class NoSuchLabelException extends RepositoryException {
super(string);
}
public NoSuchLabelException(String string, Exception e) {
super(string, e);
}
}

View File

@@ -27,4 +27,8 @@ public class RepositoryException extends RuntimeException {
super(string);
}
public RepositoryException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -146,9 +146,13 @@ public class SvnKitEnvironmentRepository extends AbstractScmEnvironmentRepositor
return version.toString();
}
catch (Exception e) {
this.logger.warn("Could not update remote for " + label + " (current local="
+ getWorkingDirectory().getPath() + "), remote: " + this.getUri()
+ ")");
String message = "Could not update remote for " + label + " (current local="
+ getWorkingDirectory().getPath() + "), remote: " + this.getUri() + ")";
if (logger.isDebugEnabled()) {
logger.debug(message, e);
} else if (logger.isWarnEnabled()) {
logger.warn(message);
}
}
final SVNStatus status = SVNClientManager.newInstance().getStatusClient()

View File

@@ -128,7 +128,7 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
private List<String> findKeys(String application, List<String> profiles) {
List<String> keys = new ArrayList<>();
if (StringUtils.hasText(this.defaultKey)) {
if (StringUtils.hasText(this.defaultKey) && !this.defaultKey.equals(application)) {
keys.add(this.defaultKey);
addProfiles(keys, this.defaultKey, profiles);
}

View File

@@ -25,8 +25,8 @@ import java.nio.charset.Charset;
import javax.servlet.http.HttpServletRequest;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UrlPathHelper;
@@ -68,10 +69,12 @@ public class ResourceController {
}
@RequestMapping("/{name}/{profile}/{label}/**")
public String resolve(@PathVariable String name, @PathVariable String profile,
@PathVariable String label, HttpServletRequest request) throws IOException {
public String retrieve(@PathVariable String name, @PathVariable String profile,
@PathVariable String label, HttpServletRequest request,
@RequestParam(defaultValue = "true") boolean resolvePlaceholders)
throws IOException {
String path = getFilePath(request, name, profile, label);
return resolve(name, profile, label, path);
return retrieve(name, profile, label, path, resolvePlaceholders);
}
private String getFilePath(HttpServletRequest request, String name, String profile,
@@ -82,21 +85,24 @@ public class ResourceController {
return path;
}
synchronized String resolve(String name, String profile, String label, String path)
throws IOException {
synchronized String retrieve(String name, String profile, String label, String path,
boolean resolvePlaceholders) throws IOException {
if (label != null && label.contains("(_)")) {
// "(_)" is uncommon in a git branch name, but "/" cannot be matched
// by Spring MVC
label = label.replace("(_)", "/");
}
StandardEnvironment environment = prepareEnvironment(
this.environmentRepository.findOne(name, profile, label));
// ensure InputStream will be closed to prevent file locks on Windows
try (InputStream is = this.resourceRepository.findOne(name, profile, label, path)
.getInputStream()) {
String text = StreamUtils.copyToString(is, Charset.forName("UTF-8"));
return resolvePlaceholders(environment, text);
if (resolvePlaceholders) {
Environment environment = this.environmentRepository.findOne(name,
profile, label);
text = resolvePlaceholders(prepareEnvironment(environment), text);
}
return text;
}
}

View File

@@ -16,8 +16,6 @@
package org.springframework.cloud.config.server.credentials;
import static org.junit.Assert.*;
import java.net.URISyntaxException;
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
@@ -30,6 +28,13 @@ import org.springframework.cloud.config.server.support.GitCredentialsProviderFac
import com.amazonaws.auth.AWSCredentialsProvider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* It would be nice to do an integration test, however, this would require
* using real AWS credentials. How can we test the credential generation

View File

@@ -16,8 +16,6 @@
package org.springframework.cloud.config.server.credentials;
import static org.junit.Assert.*;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.junit.Before;
@@ -26,6 +24,12 @@ import org.springframework.cloud.config.server.support.AwsCodeCommitCredentialPr
import org.springframework.cloud.config.server.support.GitCredentialsProviderFactory;
import org.springframework.cloud.config.server.support.PassphraseCredentialsProvider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* @author don laidlaw
*

View File

@@ -55,6 +55,21 @@ public class EncryptionControllerTests {
this.controller.decrypt("foo", MediaType.TEXT_PLAIN);
}
@Test(expected = InvalidCipherException.class)
public void shouldThrowExceptionOnDecryptInvalidData() {
this.controller = new EncryptionController(
new SingleTextEncryptorLocator(new RsaSecretEncryptor()));
controller.decrypt("foo", MediaType.TEXT_PLAIN);
}
@Test(expected = InvalidCipherException.class)
public void shouldThrowExceptionOnDecryptWrongKey() {
RsaSecretEncryptor encryptor = new RsaSecretEncryptor();
this.controller = new EncryptionController(
new SingleTextEncryptorLocator(new RsaSecretEncryptor()));
controller.decrypt(encryptor.encrypt("foo"), MediaType.TEXT_PLAIN);
}
@Test
public void sunnyDayRsaKey() {
this.controller = new EncryptionController(

View File

@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.FetchCommand;
@@ -72,7 +73,9 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -703,6 +706,27 @@ public class JGitEnvironmentRepositoryTests {
}
}
@Test
public void shouldPrintStacktraceIfDebugEnabled() throws Exception {
final Log mockLogger = mock(Log.class);
JGitEnvironmentRepository envRepository = new JGitEnvironmentRepository(this.environment){
@Override
public void afterPropertiesSet() throws Exception {
this.logger = mockLogger;
}
};
envRepository.afterPropertiesSet();
when(mockLogger.isDebugEnabled()).thenReturn(true);
envRepository.warn("", new RuntimeException());
verify(mockLogger).warn(eq(""));
verify(mockLogger).debug(eq("Stacktrace for: "), any(RuntimeException.class));
int numberOfInvocations = mockingDetails(mockLogger).getInvocations().size();
assertEquals("should call isDebugEnabled warn and debug", 3, numberOfInvocations);
}
class MockCloneCommand extends CloneCommand {
private Git mockGit;

View File

@@ -1,11 +1,8 @@
package org.springframework.cloud.config.server.environment;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
@@ -17,6 +14,8 @@ import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertEquals;
/**
* @author Spencer Gibb
* @author Ryan Baxter
@@ -27,10 +26,11 @@ public class VaultEnvironmentRepositoryTests {
public void init() {}
@Test
public void testFindOne() throws IOException {
public void testFindOneNoDefaultKey() throws IOException {
MockHttpServletRequest configRequest = new MockHttpServletRequest();
configRequest.addHeader("X-CONFIG-TOKEN", "mytoken");
RestTemplate rest = Mockito.mock(RestTemplate.class);
ResponseEntity<VaultEnvironmentRepository.VaultResponse> myAppResp = Mockito.mock(ResponseEntity.class);
Mockito.when(myAppResp.getStatusCode()).thenReturn(HttpStatus.OK);
VaultEnvironmentRepository.VaultResponse myAppVaultResp = Mockito.mock(VaultEnvironmentRepository.VaultResponse.class);
@@ -39,20 +39,104 @@ public class VaultEnvironmentRepositoryTests {
Mockito.when(rest.exchange(Mockito.eq("http://127.0.0.1:8200/v1/{backend}/{key}"),
Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class),
Mockito.eq("secret"), Mockito.eq("myapp"))).thenReturn(myAppResp);
ResponseEntity<VaultEnvironmentRepository.VaultResponse> appResp = Mockito.mock(ResponseEntity.class);
Mockito.when(appResp.getStatusCode()).thenReturn(HttpStatus.OK);
VaultEnvironmentRepository.VaultResponse appVaultResp = Mockito.mock(VaultEnvironmentRepository.VaultResponse.class);
Mockito.when(appVaultResp.getData()).thenReturn(null);
Mockito.when(appVaultResp.getData()).thenReturn("{\"def-foo\":\"def-bar\"}");
Mockito.when(appResp.getBody()).thenReturn(appVaultResp);
Mockito.when(rest.exchange(Mockito.eq("http://127.0.0.1:8200/v1/{backend}/{key}"),
Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class),
Mockito.eq("secret"), Mockito.eq("application"))).thenReturn(appResp);
VaultEnvironmentRepository repo = new VaultEnvironmentRepository(configRequest, new EnvironmentWatch.Default(), rest);
Environment e = repo.findOne("myapp", null, null);
assertEquals("myapp", e.getName());
Map<String,String> result = new HashMap<String,String>();
assertEquals("Name should be the same as the application argument", "myapp", e.getName());
assertEquals("Properties for specified application and default application with key 'application' should be returned", 2, e.getPropertySources().size());
Map<String, String> firstResult = new HashMap<String, String>();
firstResult.put("foo", "bar");
assertEquals("Properties for specified application should be returned in priority position", firstResult, e.getPropertySources().get(0).getSource());
Map<String, String> secondResult = new HashMap<String, String>();
secondResult.put("def-foo", "def-bar");
assertEquals("Properties for default application with key 'application' should be returned in second position", secondResult, e.getPropertySources().get(1).getSource());
}
@Test
public void testFindOneDefaultKeySetAndDifferentToApplication() throws IOException {
MockHttpServletRequest configRequest = new MockHttpServletRequest();
configRequest.addHeader("X-CONFIG-TOKEN", "mytoken");
RestTemplate rest = Mockito.mock(RestTemplate.class);
ResponseEntity<VaultEnvironmentRepository.VaultResponse> myAppResp = Mockito.mock(ResponseEntity.class);
Mockito.when(myAppResp.getStatusCode()).thenReturn(HttpStatus.OK);
VaultEnvironmentRepository.VaultResponse myAppVaultResp = Mockito.mock(VaultEnvironmentRepository.VaultResponse.class);
Mockito.when(myAppVaultResp.getData()).thenReturn("{\"foo\":\"bar\"}");
Mockito.when(myAppResp.getBody()).thenReturn(myAppVaultResp);
Mockito.when(rest.exchange(Mockito.eq("http://127.0.0.1:8200/v1/{backend}/{key}"),
Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class),
Mockito.eq("secret"), Mockito.eq("myapp"))).thenReturn(myAppResp);
ResponseEntity<VaultEnvironmentRepository.VaultResponse> myDefaultKeyResp = Mockito.mock(ResponseEntity.class);
Mockito.when(myDefaultKeyResp.getStatusCode()).thenReturn(HttpStatus.OK);
VaultEnvironmentRepository.VaultResponse myDefaultKeyVaultResp = Mockito.mock(VaultEnvironmentRepository.VaultResponse.class);
Mockito.when(myDefaultKeyVaultResp.getData()).thenReturn("{\"def-foo\":\"def-bar\"}");
Mockito.when(myDefaultKeyResp.getBody()).thenReturn(myDefaultKeyVaultResp);
Mockito.when(rest.exchange(Mockito.eq("http://127.0.0.1:8200/v1/{backend}/{key}"),
Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class),
Mockito.eq("secret"), Mockito.eq("mydefaultkey"))).thenReturn(myDefaultKeyResp);
VaultEnvironmentRepository repo = new VaultEnvironmentRepository(configRequest, new EnvironmentWatch.Default(), rest);
repo.setDefaultKey("mydefaultkey");
Environment e = repo.findOne("myapp", null, null);
assertEquals("Name should be the same as the application argument", "myapp", e.getName());
assertEquals("Properties for specified application and default application with key 'mydefaultkey' should be returned", 2, e.getPropertySources().size());
Map<String, String> firstResult = new HashMap<String, String>();
firstResult.put("foo", "bar");
assertEquals("Properties for specified application should be returned in priority position", firstResult, e.getPropertySources().get(0).getSource());
Map<String, String> secondResult = new HashMap<String, String>();
secondResult.put("def-foo", "def-bar");
assertEquals("Properties for default application with key 'mydefaultkey' should be returned in second position", secondResult, e.getPropertySources().get(1).getSource());
}
@Test
public void testFindOneDefaultKeySetAndEqualToApplication() throws IOException {
MockHttpServletRequest configRequest = new MockHttpServletRequest();
configRequest.addHeader("X-CONFIG-TOKEN", "mytoken");
RestTemplate rest = Mockito.mock(RestTemplate.class);
ResponseEntity<VaultEnvironmentRepository.VaultResponse> myAppResp = Mockito.mock(ResponseEntity.class);
Mockito.when(myAppResp.getStatusCode()).thenReturn(HttpStatus.OK);
VaultEnvironmentRepository.VaultResponse myAppVaultResp = Mockito.mock(VaultEnvironmentRepository.VaultResponse.class);
Mockito.when(myAppVaultResp.getData()).thenReturn("{\"foo\":\"bar\"}");
Mockito.when(myAppResp.getBody()).thenReturn(myAppVaultResp);
Mockito.when(rest.exchange(Mockito.eq("http://127.0.0.1:8200/v1/{backend}/{key}"),
Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class),
Mockito.eq("secret"), Mockito.eq("myapp"))).thenReturn(myAppResp);
ResponseEntity<VaultEnvironmentRepository.VaultResponse> appResp = Mockito.mock(ResponseEntity.class);
Mockito.when(appResp.getStatusCode()).thenReturn(HttpStatus.OK);
VaultEnvironmentRepository.VaultResponse appVaultResp = Mockito.mock(VaultEnvironmentRepository.VaultResponse.class);
Mockito.when(appVaultResp.getData()).thenReturn("{\"def-foo\":\"def-bar\"}");
Mockito.when(appResp.getBody()).thenReturn(appVaultResp);
Mockito.when(rest.exchange(Mockito.eq("http://127.0.0.1:8200/v1/{backend}/{key}"),
Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class),
Mockito.eq("secret"), Mockito.eq("application"))).thenReturn(appResp);
VaultEnvironmentRepository repo = new VaultEnvironmentRepository(configRequest, new EnvironmentWatch.Default(), rest);
repo.setDefaultKey("myapp");
Environment e = repo.findOne("myapp", null, null);
assertEquals("Name should be the same as the application argument", "myapp", e.getName());
assertEquals("Only properties for specified application should be returned", 1, e.getPropertySources().size());
Map<String, String> result = new HashMap<String, String>();
result.put("foo", "bar");
assertEquals(result, e.getPropertySources().get(0).getSource());
assertEquals("Properties should be returned for specified application", result, e.getPropertySources().get(0).getSource());
}
@Test(expected = IllegalArgumentException.class)

View File

@@ -62,9 +62,16 @@ public class ResourceControllerTests {
@Test
public void templateReplacement() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
String resource = this.controller.resolve("foo", "bar", "dev", "template.json");
String resource = this.controller.retrieve("foo", "bar", "dev", "template.json", true);
assertTrue("Wrong content: " + resource, resource.matches("\\{\\s*\"foo\": \"dev_bar\"\\s*\\}"));
}
@Test
public void templateReplacementNotForResolvePlaceholdersFalse() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
String resource = this.controller.retrieve("foo", "bar", "dev", "template.json", false);
assertTrue("Wrong content: " + resource, resource.matches("\\{\\s*\"foo\": \"\\$\\{foo\\}\"\\s*\\}"));
}
@Test
public void templateReplacementNotForBinary() throws Exception {
@@ -76,21 +83,21 @@ public class ResourceControllerTests {
@Test
public void escapedPlaceholder() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
String resource = this.controller.resolve("foo", "bar", "dev", "placeholder.txt");
String resource = this.controller.retrieve("foo", "bar", "dev", "placeholder.txt", true);
assertEquals("foo: ${foo}", resource);
}
@Test
public void labelWithSlash() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
String resource = this.controller.resolve("foo", "bar", "dev(_)spam", "foo.txt");
String resource = this.controller.retrieve("foo", "bar", "dev(_)spam", "foo.txt", true);
assertEquals("foo: dev_bar/spam", resource);
}
@Test
public void resourceWithSlash() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
String resource = this.controller.resolve("foo", "bar", "dev", "spam/foo.txt");
String resource = this.controller.retrieve("foo", "bar", "dev", "spam/foo.txt", true);
assertEquals("foo: dev_bar/spam", resource);
}
@@ -99,7 +106,7 @@ public class ResourceControllerTests {
this.environmentRepository.setSearchLocations("classpath:/test");
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/foo/bar/dev/" + "spam/foo.txt");
String resource = this.controller.resolve("foo", "bar", "dev", request);
String resource = this.controller.retrieve("foo", "bar", "dev", request, true);
assertEquals("foo: dev_bar/spam", resource);
}
@@ -109,10 +116,33 @@ public class ResourceControllerTests {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setServletPath("/spring");
request.setRequestURI("/foo/bar/dev/" + "spam/foo.txt");
String resource = this.controller.resolve("foo", "bar", "dev", request);
String resource = this.controller.retrieve("foo", "bar", "dev", request, true);
assertEquals("foo: dev_bar/spam", resource);
}
@Test
public void labelWithSlashForResolvePlaceholdersFalse() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
String resource = this.controller.retrieve("foo", "bar", "dev(_)spam", "foo.txt", false);
assertEquals("foo: dev_bar/spam", resource);
}
@Test
public void resourceWithSlashForResolvePlaceholdersFalse() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
String resource = this.controller.retrieve("foo", "bar", "dev", "spam/foo.txt", false);
assertEquals("foo: dev_bar/spam", resource);
}
@Test
public void resourceWithSlashForResolvePlaceholdersFalseRequest() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/foo/bar/dev/" + "spam/foo.txt");
String resource = this.controller.retrieve("foo", "bar", "dev", request, false);
assertEquals("foo: dev_bar/spam", resource);
}
@Test
public void labelWithSlashForBinary() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");