Add ResourceController for serving plain text config files

Can be adapted to serve content in any format (e.g. nginx config file,
XML configuration for logger, etc.) - basically anything that can be
stored in plain text and doesn't require streaming.

Fixes gh-147, see also gh-198
This commit is contained in:
Dave Syer
2015-09-30 13:50:37 +01:00
parent 02a9eb3cd7
commit 62846bda84
27 changed files with 738 additions and 124 deletions

View File

@@ -1,12 +1,16 @@
package org.springframework.cloud.config.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyString;
import java.io.IOException;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -20,15 +24,11 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyString;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@IntegrationTest("server.port:0")
@@ -50,27 +50,34 @@ public class ConfigClientOffIntegrationTests {
@Test
public void contextLoads() {
Environment environment = new TestRestTemplate().getForObject("http://localhost:"
+ port + "/foo/development/", Environment.class);
+ this.port + "/foo/development/", Environment.class);
assertTrue(environment.getPropertySources().isEmpty());
}
@Test
public void configClientDisabled() throws Exception {
assertEquals(0, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
assertEquals(0, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.context,
ConfigServicePropertySourceLocator.class).length);
}
@Configuration
@Import(ConfigServerApplication.class)
protected static class TestConfiguration {
@Bean
public EnvironmentRepository environmentRepository() {
EnvironmentRepository repository = Mockito.mock(EnvironmentRepository.class);
given(repository.findOne(anyString(), anyString(), anyString())).willReturn(new Environment("", ""));
return repository;
}
@Bean
public ResourceRepository resourceRepository() {
ResourceRepository repository = Mockito.mock(ResourceRepository.class);
given(repository.findOne(anyString(), anyString(), anyString(), anyString())).willReturn(new ByteArrayResource("".getBytes()));
return repository;
}
}
}

View File

@@ -1,12 +1,16 @@
package org.springframework.cloud.config.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyString;
import java.io.IOException;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -20,15 +24,11 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyString;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@IntegrationTest({ "server.port:0", "spring.cloud.config.enabled:true" })
@@ -50,27 +50,34 @@ public class ConfigClientOnIntegrationTests {
@Test
public void contextLoads() {
Environment environment = new TestRestTemplate().getForObject("http://localhost:"
+ port + "/foo/development/", Environment.class);
+ this.port + "/foo/development/", Environment.class);
assertTrue(environment.getPropertySources().isEmpty());
}
@Test
public void configClientEnabled() throws Exception {
assertEquals(1, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
assertEquals(1, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.context,
ConfigServicePropertySourceLocator.class).length);
}
@Configuration
@Import(ConfigServerApplication.class)
protected static class TestConfiguration {
@Bean
public EnvironmentRepository environmentRepository() {
EnvironmentRepository repository = Mockito.mock(EnvironmentRepository.class);
given(repository.findOne(anyString(), anyString(), anyString())).willReturn(new Environment("", ""));
return repository;
}
@Bean
public ResourceRepository resourceRepository() {
ResourceRepository repository = Mockito.mock(ResourceRepository.class);
given(repository.findOne(anyString(), anyString(), anyString(), anyString())).willReturn(new ByteArrayResource("".getBytes()));
return repository;
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2015 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 static org.junit.Assert.assertNotNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @author Dave Syer
*
*/
public class GenericResourceRepositoryTests {
private GenericResourceRepository repository;
private ConfigurableApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Before
public void init() {
this.context = new SpringApplicationBuilder(
NativeEnvironmentRepositoryTests.class).web(false).run();
this.repository = new GenericResourceRepository(
new NativeEnvironmentRepository(this.context.getEnvironment()));
this.repository.setResourceLoader(this.context);
this.context.close();
}
@Test
public void locateResource() {
assertNotNull(this.repository.findOne("blah", "default", "master", "foo.properties"));
}
@Test
public void locateProfiledResource() {
assertNotNull(this.repository.findOne("blah", "local", "master", "foo.txt"));
}
@Test(expected=NoSuchResourceException.class)
public void locateMissingResource() {
assertNotNull(this.repository.findOne("blah", "default", "master", "foo.txt"));
}
}

View File

@@ -71,7 +71,7 @@ public class NativeEnvironmentRepositoryTests {
this.repository.setSearchLocations("classpath:/test");
Environment environment = this.repository.findOne("foo", "development", "dev");
assertEquals(3, environment.getPropertySources().size());
// position 1 because it has higher precendence than anything except the
// position 1 because it has higher precedence than anything except the
// foo-development.properties
assertEquals("dev_bar",
environment.getPropertySources().get(1).getSource().get("foo"));

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2015 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 static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @author Dave Syer
*
*/
public class ResourceControllerTests {
private ResourceController controller;
private GenericResourceRepository repository;
private ConfigurableApplicationContext context;
private NativeEnvironmentRepository environmentRepository;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Before
public void init() {
this.context = new SpringApplicationBuilder(
NativeEnvironmentRepositoryTests.class).web(false).run();
this.environmentRepository = new NativeEnvironmentRepository(
this.context.getEnvironment());
this.repository = new GenericResourceRepository(this.environmentRepository);
this.repository.setResourceLoader(this.context);
this.controller = new ResourceController(this.repository,
new EnvironmentController(this.environmentRepository));
this.context.close();
}
@Test
public void templateReplacement() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
String resource = this.controller.resolve("foo", "bar", "dev", "template.json");
assertEquals("{\n \"foo\": \"dev_bar\"\n}", resource);
}
@Test
public void escapedPlaceholder() throws Exception {
this.environmentRepository.setSearchLocations("classpath:/test");
String resource = this.controller.resolve("foo", "bar", "dev", "placeholder.txt");
assertEquals("foo: ${foo}", resource);
}
}

View File

@@ -5,7 +5,4 @@ spring:
git:
basedir: target/config
overrides:
spring:
cloud:
config:
enabled: true
spring.cloud.config.enabled: true

View File

@@ -0,0 +1 @@
foo: local

View File

@@ -0,0 +1 @@
foo: \${foo}

View File

@@ -0,0 +1,3 @@
{
"foo": "${foo}"
}