Extract former config-client features to a new spring-cloud-context

Fixes gh-14
This commit is contained in:
Dave Syer
2015-03-19 11:52:25 +00:00
parent 0b0999fde8
commit 7d480ab41b
120 changed files with 1373 additions and 54 deletions

View File

@@ -0,0 +1,35 @@
package org.springframework.cloud.bootstrap;
import static org.junit.Assert.assertFalse;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.bootstrap.BootstrapDisabledAutoConfigurationIntegrationTests.Application;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@IntegrationTest("spring.cloud.bootstrap.enabled:false")
public class BootstrapDisabledAutoConfigurationIntegrationTests {
@Autowired
private ConfigurableEnvironment environment;
@Test
public void noBootstrapProperties() {
assertFalse(environment.getPropertySources().contains("bootstrap"));
}
@EnableAutoConfiguration
@Configuration
protected static class Application {
}
}

View File

@@ -0,0 +1,48 @@
package org.springframework.cloud.bootstrap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.bootstrap.BootstrapOrderingAutoConfigurationIntegrationTests.Application;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@IntegrationTest("encrypt.key:deadbeef")
@ActiveProfiles("encrypt")
public class BootstrapOrderingAutoConfigurationIntegrationTests {
@Autowired
private ConfigurableEnvironment environment;
@Test
public void bootstrapPropertiesExist() {
assertTrue(environment.getPropertySources().contains("bootstrap"));
}
@Test
public void normalPropertiesDecrypted() {
assertEquals("foo", environment.resolvePlaceholders("${foo}"));
}
@Test
public void bootstrapPropertiesDecrypted() {
assertEquals("bar", environment.resolvePlaceholders("${bar}"));
}
@EnableAutoConfiguration
@Configuration
protected static class Application {
}
}

View File

@@ -0,0 +1,323 @@
/*
* Copyright 2013-2014 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.bootstrap.config;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
/**
* @author Dave Syer
*
*/
public class BootstrapConfigurationTests {
private ConfigurableApplicationContext context;
@Rule
public ExpectedException expected = ExpectedException.none();
@After
public void close() {
// Expected.* is bound to the PropertySourceConfiguration below
System.clearProperty("expected.name");
System.clearProperty("expected.fail");
// Used to test system properties override
System.clearProperty("bootstrap.foo");
PropertySourceConfiguration.MAP.clear();
if (this.context != null) {
this.context.close();
}
}
@Test
public void pickupExternalBootstrapProperties() {
String externalPropertiesPath = getExternalProperties();
this.context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class)
.properties("spring.cloud.bootstrap.location:" + externalPropertiesPath)
.run();
assertEquals("externalPropertiesInfoName", this.context.getEnvironment()
.getProperty("info.name"));
assertTrue(this.context.getEnvironment().getPropertySources()
.contains("bootstrap"));
}
/**
* Running the test from maven will start from a different directory then starting it
* from intellij
*
* @return
*/
private String getExternalProperties() {
String externalPropertiesPath = "";
File externalProperties = new File(
"src/test/resources/external-properties/bootstrap.properties");
if (externalProperties.exists()) {
externalPropertiesPath = externalProperties.getAbsolutePath();
}
else {
externalProperties = new File(
"spring-cloud-config-client/src/test/resources/external-properties/bootstrap.properties");
externalPropertiesPath = externalProperties.getAbsolutePath();
}
return externalPropertiesPath;
}
@Test
public void picksUpAdditionalPropertySource() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
System.setProperty("expected.name", "bootstrap");
this.context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
assertEquals("bar", this.context.getEnvironment().getProperty("bootstrap.foo"));
assertTrue(this.context.getEnvironment().getPropertySources()
.contains("bootstrap"));
}
@Test
public void failsOnPropertySource() {
System.setProperty("expected.fail", "true");
this.expected.expectMessage("Planned");
this.context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
}
@Test
public void overrideSystemPropertySourceByDefault() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
System.setProperty("bootstrap.foo", "system");
this.context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
assertEquals("bar", this.context.getEnvironment().getProperty("bootstrap.foo"));
}
@Test
public void systemPropertyOverrideFalse() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put(
"spring.cloud.config.overrideSystemProperties", "false");
System.setProperty("bootstrap.foo", "system");
this.context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
assertEquals("system", this.context.getEnvironment().getProperty("bootstrap.foo"));
}
@Test
public void systemPropertyOverrideWhenOverrideDisallowed() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put(
"spring.cloud.config.overrideSystemProperties", "false");
// If spring.cloud.config.allowOverride=false is in the remote property sources
// with sufficiently high priority it always wins. Admins can enforce it by adding
// their own remote property source.
PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "false");
System.setProperty("bootstrap.foo", "system");
this.context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
assertEquals("bar", this.context.getEnvironment().getProperty("bootstrap.foo"));
}
@Test
public void applicationNameInBootstrapAndMain() {
System.setProperty("expected.name", "main");
this.context = new SpringApplicationBuilder()
.web(false)
.properties("spring.cloud.bootstrap.name:other",
"spring.config.name:plain").sources(BareConfiguration.class)
.run();
assertEquals("app",
this.context.getEnvironment().getProperty("spring.application.name"));
// The parent is called "main" because spring.application.name is specified in
// other.properties (the bootstrap properties)
assertEquals(
"main",
this.context.getParent().getEnvironment()
.getProperty("spring.application.name"));
// The bootstrap context has a different "bootstrap" property source
assertNotSame(
this.context.getEnvironment().getPropertySources().get("bootstrap"),
((ConfigurableEnvironment) this.context.getParent().getEnvironment())
.getPropertySources().get("bootstrap"));
assertEquals("app", this.context.getId());
}
@Test
public void applicationNameNotInBootstrap() {
System.setProperty("expected.name", "main");
this.context = new SpringApplicationBuilder()
.web(false)
.properties("spring.cloud.bootstrap.name:application",
"spring.config.name:other").sources(BareConfiguration.class)
.run();
assertEquals("main",
this.context.getEnvironment().getProperty("spring.application.name"));
// The parent is called "application" because spring.application.name is not
// defined in the bootstrap properties
assertEquals("application", this.context.getParent().getEnvironment()
.getProperty("spring.application.name"));
}
@Test
public void applicationNameOnlyInBootstrap() {
System.setProperty("expected.name", "main");
this.context = new SpringApplicationBuilder().web(false)
.properties("spring.cloud.bootstrap.name:other")
.sources(BareConfiguration.class).run();
// The main context is called "main" because spring.application.name is specified
// in other.properties (and not in the main config file)
assertEquals("main",
this.context.getEnvironment().getProperty("spring.application.name"));
// The parent is called "main" because spring.application.name is specified in
// other.properties (the bootstrap properties this time)
assertEquals(
"main",
this.context.getParent().getEnvironment()
.getProperty("spring.application.name"));
assertEquals("main", this.context.getId());
}
@Test
public void environmentEnrichedOnceWhenSharedWithChildContext() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
this.context = new SpringApplicationBuilder().sources(BareConfiguration.class)
.environment(new StandardEnvironment()).child(BareConfiguration.class)
.web(false).run();
assertEquals("bar", this.context.getEnvironment().getProperty("bootstrap.foo"));
assertEquals(this.context.getEnvironment(), this.context.getParent()
.getEnvironment());
MutablePropertySources sources = this.context.getEnvironment()
.getPropertySources();
PropertySource<?> bootstrap = sources.get("bootstrap");
assertNotNull(bootstrap);
assertEquals(0, sources.precedenceOf(bootstrap));
}
@Test
public void environmentEnrichedInParentContext() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
this.context = new SpringApplicationBuilder().sources(BareConfiguration.class)
.child(BareConfiguration.class).web(false).run();
assertEquals("bar", this.context.getEnvironment().getProperty("bootstrap.foo"));
assertNotSame(this.context.getEnvironment(), this.context.getParent()
.getEnvironment());
assertTrue(this.context.getEnvironment().getPropertySources()
.contains("bootstrap"));
assertTrue(((ConfigurableEnvironment) this.context.getParent().getEnvironment())
.getPropertySources().contains("bootstrap"));
}
@Test
public void differentProfileInChild() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
// Profiles are always merged with the child
ConfigurableApplicationContext parent = new SpringApplicationBuilder()
.sources(BareConfiguration.class).profiles("parent").web(false).run();
this.context = new SpringApplicationBuilder(BareConfiguration.class)
.profiles("child").parent(parent).web(false).run();
assertNotSame(this.context.getEnvironment(), this.context.getParent()
.getEnvironment());
// The ApplicationContext merges profiles (profiles and property sources), see
// AbstractEnvironment.merge()
assertTrue(this.context.getEnvironment().acceptsProfiles("child", "parent"));
// But the parent is not a child
assertFalse(this.context.getParent().getEnvironment().acceptsProfiles("child"));
assertTrue(this.context.getParent().getEnvironment().acceptsProfiles("parent"));
assertTrue(((ConfigurableEnvironment) this.context.getParent().getEnvironment())
.getPropertySources().contains("bootstrap"));
assertEquals("bar", this.context.getEnvironment().getProperty("bootstrap.foo"));
// The "bootstrap" property source is not shared now, but it has the same
// properties in it because they are pulled from the PropertySourceConfiguration
// below
assertEquals("bar",
this.context.getParent().getEnvironment().getProperty("bootstrap.foo"));
// The parent property source is there in the child because they are both in the
// "parent" profile (by virtue of the merge in AbstractEnvironment)
assertEquals("parent", this.context.getEnvironment().getProperty("info.name"));
}
@Configuration
@EnableConfigurationProperties
protected static class BareConfiguration {
}
@Configuration
@ConfigurationProperties("expected")
// This is added to bootstrap context as a source in bootstrap.properties
protected static class PropertySourceConfiguration implements PropertySourceLocator {
public static Map<String, Object> MAP = new HashMap<String, Object>(
Collections.<String, Object> singletonMap("bootstrap.foo", "bar"));
private String name;
private boolean fail = false;
@Override
public PropertySource<?> locate(Environment environment) {
if (this.name != null) {
assertEquals(this.name,
environment.getProperty("spring.application.name"));
}
if (this.fail) {
throw new RuntimeException("Planned");
}
return new MapPropertySource("testBootstrap", MAP);
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public boolean isFail() {
return this.fail;
}
public void setFail(boolean fail) {
this.fail = fail;
}
}
}

View File

@@ -0,0 +1,24 @@
package org.springframework.cloud.bootstrap.encrypt;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.security.crypto.encrypt.TextEncryptor;
public class EncryptionBootstrapConfigurationTests {
@Test
public void rsaKeyStore() {
ConfigurableApplicationContext context = new SpringApplicationBuilder(
EncryptionBootstrapConfiguration.class).web(false).properties(
"encrypt.keyStore.location:classpath:/server.jks",
"encrypt.keyStore.password:letmein",
"encrypt.keyStore.alias:mytestkey", "encrypt.keyStore.secret:changeme")
.run();
TextEncryptor encryptor = context.getBean(TextEncryptor.class);
assertEquals("foo", encryptor.decrypt(encryptor.encrypt("foo")));
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2013-2014 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.bootstrap.encrypt;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.security.crypto.encrypt.Encryptors;
/**
* @author Dave Syer
*
*/
public class EnvironmentDecryptApplicationListenerTests {
private EnvironmentDecryptApplicationInitializer listener = new EnvironmentDecryptApplicationInitializer(Encryptors.noOpText());
@Test
public void decryptCipherKey() {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar");
listener.initialize(context);
assertEquals("bar", context.getEnvironment().getProperty("foo"));
}
@Test(expected=IllegalStateException.class)
public void errorOnDecrypt() {
listener = new EnvironmentDecryptApplicationInitializer(Encryptors.text("deadbeef", "AFFE37"));
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar");
listener.initialize(context);
assertEquals("bar", context.getEnvironment().getProperty("foo"));
}
@Test
public void errorOnDecryptWithEmpty() {
listener = new EnvironmentDecryptApplicationInitializer(Encryptors.text("deadbeef", "AFFE37"));
listener.setFailOnError(false);
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar");
listener.initialize(context);
// Empty is safest fallback for undecryptable cipher
assertEquals("", context.getEnvironment().getProperty("foo"));
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2006-2007 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.context.environment;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import javax.servlet.ServletException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.context.environment.EnvironmentManagerIntegrationTests.TestConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class EnvironmentManagerIntegrationTests {
@Autowired
private TestProperties properties;
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setUp() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
@Test
public void testRefresh() throws Exception {
assertEquals("Hello scope!", properties.getMessage());
// Change the dynamic property source...
this.mvc.perform(post("/env").param("message", "Foo")).andExpect(status().isOk()).andExpect(
content().string("{\"message\":\"Foo\"}"));
assertEquals("Foo", properties.getMessage());
}
@Test
public void testRefreshFails() throws Exception {
try {
this.mvc.perform(post("/env").param("delay", "foo")).andExpect(
status().is5xxServerError());
fail("expected ServletException");
} catch (ServletException e) {
// The underlying BindException is not handled by the dispatcher servlet
}
assertEquals(0, properties.getDelay());
}
public static void main(String[] args) {
SpringApplication.run(TestConfiguration.class, args);
}
@Configuration
@EnableAutoConfiguration
protected static class TestConfiguration {
@Bean
protected TestProperties properties() {
return new TestProperties();
}
}
@ConfigurationProperties
protected static class TestProperties {
private String message;
private int delay;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getDelay() {
return delay;
}
public void setDelay(int delay) {
this.delay = delay;
}
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2006-2007 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.context.properties;
import static org.junit.Assert.assertEquals;
import javax.annotation.PostConstruct;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.context.properties.ConfigurationPropertiesRebinderIntegrationTests.TestConfiguration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SpringApplicationConfiguration(classes=TestConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ConfigurationPropertiesRebinderIntegrationTests {
@Autowired
private TestProperties properties;
@Autowired
private ConfigurationPropertiesRebinder rebinder;
@Autowired
private ConfigurableEnvironment environment;
@Test
@DirtiesContext
public void testSimpleProperties() throws Exception {
assertEquals("Hello scope!", properties.getMessage());
// Change the dynamic property source...
EnvironmentTestUtils.addEnvironment(environment, "message:Foo");
// ...but don't refresh, so the bean stays the same:
assertEquals("Hello scope!", properties.getMessage());
assertEquals(1, properties.getCount());
}
@Test
@DirtiesContext
public void testRefresh() throws Exception {
assertEquals(1, properties.getCount());
assertEquals("Hello scope!", properties.getMessage());
// Change the dynamic property source...
EnvironmentTestUtils.addEnvironment(environment, "message:Foo");
// ...and then refresh, so the bean is re-initialized:
rebinder.rebind();
assertEquals("Foo", properties.getMessage());
assertEquals(2, properties.getCount());
}
@Configuration
@EnableConfigurationProperties
@Import({RefreshAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class})
protected static class TestConfiguration {
@Bean
protected TestProperties properties() {
return new TestProperties();
}
}
@ConfigurationProperties
protected static class TestProperties {
private String message;
private int delay;
private int count = 0;
public int getCount() {
return count;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getDelay() {
return delay;
}
public void setDelay(int delay) {
this.delay = delay;
}
@PostConstruct
public void init() {
this.count ++;
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2006-2007 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.context.restart;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
public class RestartIntegrationTests {
private ConfigurableApplicationContext context;
@After
public void close() {
if (context != null) {
context.close();
}
}
@Test
public void testRestartTwice() throws Exception {
context = SpringApplication.run(TestConfiguration.class, "--endpoints.restart.enabled=true", "--server.port=0");
RestartEndpoint endpoint = context.getBean(RestartEndpoint.class);
assertNotNull(context.getParent());
assertNull(context.getParent().getParent());
context = endpoint.restart();
assertNotNull(context);
assertNotNull(context.getParent());
assertNull(context.getParent().getParent());
RestartEndpoint next = context.getBean(RestartEndpoint.class);
assertNotSame(endpoint, next);
context = next.restart();
assertNotNull(context);
assertNotNull(context.getParent());
assertNull(context.getParent().getParent());
}
public static void main(String[] args) {
SpringApplication.run(TestConfiguration.class, args);
}
@Configuration
@EnableAutoConfiguration
protected static class TestConfiguration {
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2006-2007 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.context.scope.refresh;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.refresh.ImportRefreshScopeIntegrationTests.TestConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ImportRefreshScopeIntegrationTests {
@Autowired
private ConfigurableListableBeanFactory beanFactory;
@Autowired
private ExampleService service;
@Autowired
private org.springframework.cloud.context.scope.refresh.RefreshScope scope;
@Test
public void testSimpleProperties() throws Exception {
assertEquals("Hello scope!", service.getMessage());
assertEquals("refresh", beanFactory.getBeanDefinition("scopedTarget.service").getScope());
assertEquals("Hello scope!", service.getMessage());
}
@Configuration("service")
@RefreshScope
public static class ExampleService {
public String getMessage() {
return "Hello scope!";
}
}
@Configuration
@Import({ RefreshAutoConfiguration.class, ExampleService.class })
protected static class TestConfiguration {
}
}

View File

@@ -0,0 +1,230 @@
/*
* Copyright 2006-2007 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.context.scope.refresh;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.refresh.MoreRefreshScopeIntegrationTests.TestConfiguration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class MoreRefreshScopeIntegrationTests {
@Autowired
private TestService service;
@Autowired
private TestProperties properties;
@Autowired
private org.springframework.cloud.context.scope.refresh.RefreshScope scope;
@Autowired
private ConfigurableEnvironment environment;
@Before
public void init() {
TestService.reset();
}
@Test
@DirtiesContext
public void testSimpleProperties() throws Exception {
assertEquals("Hello scope!", service.getMessage());
assertTrue(service instanceof Advised);
// Change the dynamic property source...
EnvironmentTestUtils.addEnvironment(environment, "message:Foo");
// ...but don't refresh, so the bean stays the same:
assertEquals("Hello scope!", service.getMessage());
assertEquals(1, TestService.getInitCount());
assertEquals(0, TestService.getDestroyCount());
}
@Test
@DirtiesContext
public void testRefresh() throws Exception {
assertEquals("Hello scope!", service.getMessage());
String id1 = service.toString();
// Change the dynamic property source...
EnvironmentTestUtils.addEnvironment(environment, "message:Foo");
// ...and then refresh, so the bean is re-initialized:
scope.refreshAll();
String id2 = service.toString();
assertEquals("Foo", service.getMessage());
assertEquals(2, TestService.getInitCount());
assertEquals(1, TestService.getDestroyCount());
assertNotSame(id1, id2);
}
@Test
@DirtiesContext
public void testRefreshFails() throws Exception {
assertEquals("Hello scope!", service.getMessage());
// Change the dynamic property source...
EnvironmentTestUtils.addEnvironment(environment, "message:Foo", "delay:foo");
// ...and then refresh, so the bean is re-initialized:
scope.refreshAll();
try {
// If a refresh fails (e.g. a binding error in this case) the application is
// basically hosed.
assertEquals("Hello scope!", service.getMessage());
fail("expected BeanCreationException");
} catch (BeanCreationException e) {
}
// But we can fix it by fixing the binding error:
EnvironmentTestUtils.addEnvironment(environment, "delay:0");
// ...and then refresh, so the bean is re-initialized:
scope.refreshAll();
assertEquals("Foo", service.getMessage());
}
public static class TestService implements InitializingBean, DisposableBean {
private static Log logger = LogFactory.getLog(TestService.class);
private volatile static int initCount = 0;
private volatile static int destroyCount = 0;
private String message = null;
private volatile long delay = 0;
public void setDelay(long delay) {
this.delay = delay;
}
public void afterPropertiesSet() throws Exception {
logger.debug("Initializing message: " + message);
initCount++;
}
public void destroy() throws Exception {
logger.debug("Destroying message: " + message);
destroyCount++;
message = null;
}
public static void reset() {
initCount = 0;
destroyCount = 0;
}
public static int getInitCount() {
return initCount;
}
public static int getDestroyCount() {
return destroyCount;
}
public void setMessage(String message) {
logger.debug("Setting message: " + message);
this.message = message;
}
public String getMessage() {
logger.debug("Getting message: " + message);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
logger.info("Returning message: " + message);
return message;
}
}
@Configuration
@EnableConfigurationProperties
@Import({ RefreshAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected static class TestConfiguration {
@Bean
@RefreshScope
protected TestProperties properties() {
return new TestProperties();
}
@Bean
@RefreshScope
public TestService service() {
TestService service = new TestService();
service.setMessage(properties().getMessage());
service.setDelay(properties().getDelay());
return service;
}
}
@ConfigurationProperties
@ManagedResource
protected static class TestProperties {
private String message;
private int delay;
@ManagedAttribute
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@ManagedAttribute
public int getDelay() {
return delay;
}
public void setDelay(int delay) {
this.delay = delay;
}
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2013-2014 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.context.scope.refresh;
import static org.junit.Assert.assertEquals;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.refresh.RefreshEndpointIntegrationTests.ClientApp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Dave Syer
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ClientApp.class)
@IntegrationTest("server.port:0")
@WebAppConfiguration
public class RefreshEndpointIntegrationTests {
@Value("${local.server.port}")
private int port;
@Test
public void webAccess() throws Exception {
TestRestTemplate template = new TestRestTemplate();
template.exchange(
getUrlEncodedEntity("http://localhost:" + port + "/env", "message",
"Hello Dave!"), String.class);
template.postForObject("http://localhost:" + port + "/refresh", "", String.class);
String message = template.getForObject("http://localhost:" + port + "/",
String.class);
assertEquals("Hello Dave!", message);
}
private RequestEntity<?> getUrlEncodedEntity(String uri, String key, String value)
throws URISyntaxException {
MultiValueMap<String, String> env = new LinkedMultiValueMap<String, String>(
Collections.singletonMap("message", Arrays.asList("Hello Dave!")));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
RequestEntity<MultiValueMap<String, String>> entity = new RequestEntity<MultiValueMap<String, String>>(
env, headers, HttpMethod.POST, new URI(uri));
return entity;
}
@Configuration
@EnableAutoConfiguration
protected static class ClientApp {
@Bean
@RefreshScope
public Controller controller() {
return new Controller();
}
public static void main(String[] args) {
SpringApplication.run(ClientApp.class, args);
}
}
@RestController
protected static class Controller {
@Value("${message:Hello World!}")
String message;
@RequestMapping("/")
public String hello() {
return message;
}
}
}

View File

@@ -0,0 +1,185 @@
/*
* Copyright 2006-2007 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.context.scope.refresh;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.refresh.RefreshScopeConcurrencyTests.TestConfiguration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SpringApplicationConfiguration(classes=TestConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class RefreshScopeConcurrencyTests {
private static Log logger = LogFactory.getLog(RefreshScopeConcurrencyTests.class);
private ExecutorService executor = Executors.newSingleThreadExecutor();
@Autowired
private Service service;
@Autowired
private TestProperties properties;
@Autowired
private org.springframework.cloud.context.scope.refresh.RefreshScope scope;
@Test
@Repeat(10)
@DirtiesContext
public void testConcurrentRefresh() throws Exception {
assertEquals("Hello scope!", service.getMessage());
properties.setMessage("Foo");
properties.setDelay(500);
final CountDownLatch latch = new CountDownLatch(1);
Future<String> result = executor.submit(new Callable<String>() {
public String call() throws Exception {
logger.debug("Background started.");
try {
return service.getMessage();
} finally {
latch.countDown();
logger.debug("Background done.");
}
}
});
assertTrue(latch.await(1500, TimeUnit.MILLISECONDS));
logger.info("Refreshing");
scope.refreshAll();
assertEquals("Foo", service.getMessage());
/*
* This is the most important assertion: we don't want a null value because that means the bean was destroyed
* and not re-initialized before we accessed it.
*/
assertNotNull(result.get());
assertEquals("Hello scope!", result.get());
}
public static interface Service {
String getMessage();
}
public static class ExampleService implements Service, InitializingBean, DisposableBean {
private static Log logger = LogFactory.getLog(ExampleService.class);
private String message = null;
private volatile long delay = 0;
public void setDelay(long delay) {
this.delay = delay;
}
public void afterPropertiesSet() throws Exception {
logger.debug("Initializing message: " + message);
}
public void destroy() throws Exception {
logger.debug("Destroying message: " + message);
message = null;
}
public void setMessage(String message) {
logger.debug("Setting message: " + message);
this.message = message;
}
public String getMessage() {
logger.debug("Getting message: " + message);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
logger.info("Returning message: " + message);
return message;
}
}
@Configuration
@EnableConfigurationProperties(TestProperties.class)
@Import({RefreshAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class})
protected static class TestConfiguration {
@Autowired
private TestProperties properties;
@Bean
@RefreshScope
public ExampleService service() {
ExampleService service = new ExampleService();
service.setMessage(properties.getMessage());
service.setDelay(properties.getDelay());
return service;
}
}
@ConfigurationProperties
@ManagedResource
protected static class TestProperties {
private String message;
private int delay;
@ManagedAttribute
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@ManagedAttribute
public int getDelay() {
return delay;
}
public void setDelay(int delay) {
this.delay = delay;
}
}
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright 2013-2014 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.context.scope.refresh;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.environment.EnvironmentManager;
import org.springframework.cloud.context.scope.refresh.RefreshScopeConfigurationTests.NestedApp.NestedController;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Dave Syer
*
*/
public class RefreshScopeConfigurationTests {
private AnnotationConfigApplicationContext context;
@Rule
public ExpectedException expected = ExpectedException.none();
@After
public void init() {
if (context!=null) {
context.close();
}
}
private void refresh() {
EnvironmentManager environmentManager = context.getBean(EnvironmentManager.class);
environmentManager.setProperty("message", "Hello Dave!");
org.springframework.cloud.context.scope.refresh.RefreshScope scope = context.getBean(org.springframework.cloud.context.scope.refresh.RefreshScope.class);
scope.refreshAll();
}
/**
* See gh-43
*/
@Test
public void configurationWithRefreshScope() throws Exception {
context = new AnnotationConfigApplicationContext(Application.class,
PropertyPlaceholderAutoConfiguration.class, RefreshAutoConfiguration.class);
Application application = context.getBean(Application.class);
assertEquals("refresh", context.getBeanDefinition("scopedTarget.application").getScope());
application.hello();
refresh();
String message = application.hello();
assertEquals("Hello Dave!", message);
}
@Test
public void refreshScopeOnBean() throws Exception {
context = new AnnotationConfigApplicationContext(ClientApp.class,
PropertyPlaceholderAutoConfiguration.class, RefreshAutoConfiguration.class);
Controller application = context.getBean(Controller.class);
application.hello();
refresh();
String message = application.hello();
assertEquals("Hello Dave!", message);
}
@Test
public void refreshScopeOnNested() throws Exception {
context = new AnnotationConfigApplicationContext(NestedApp.class,
PropertyPlaceholderAutoConfiguration.class, RefreshAutoConfiguration.class);
NestedController application = context.getBean(NestedController.class);
application.hello();
refresh();
String message = application.hello();
assertEquals("Hello Dave!", message);
}
// WTF? Maven can't compile without the FQN on this one (not the others).
@org.springframework.context.annotation.Configuration
protected static class NestedApp {
@RestController
@RefreshScope
protected static class NestedController {
@Value("${message:Hello World!}")
String message;
@RequestMapping("/")
public String hello() {
return message;
}
}
public static void main(String[] args) {
SpringApplication.run(ClientApp.class, args);
}
}
@Configuration("application")
@RefreshScope
protected static class Application {
@Value("${message:Hello World!}")
String message = "Hello World";
@RequestMapping("/")
public String hello() {
return message;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Configuration
protected static class ClientApp {
@Bean
@RefreshScope
public Controller controller() {
return new Controller();
}
public static void main(String[] args) {
SpringApplication.run(ClientApp.class, args);
}
}
@RestController
protected static class Controller {
@Value("${message:Hello World!}")
String message;
@RequestMapping("/")
public String hello() {
return message;
}
}
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright 2006-2007 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.context.scope.refresh;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.GenericScope;
import org.springframework.cloud.context.scope.refresh.RefreshScopeIntegrationTests.TestConfiguration;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class RefreshScopeIntegrationTests {
@Autowired
private Service service;
@Autowired
private TestProperties properties;
@Autowired
private org.springframework.cloud.context.scope.refresh.RefreshScope scope;
@Before
public void init() {
ExampleService.reset();
}
@Test
@DirtiesContext
public void testSimpleProperties() throws Exception {
assertEquals("Hello scope!", service.getMessage());
assertTrue(service instanceof Advised);
// Change the dynamic property source...
properties.setMessage("Foo");
// ...but don't refresh, so the bean stays the same:
assertEquals("Hello scope!", service.getMessage());
assertEquals(1, ExampleService.getInitCount());
assertEquals(0, ExampleService.getDestroyCount());
}
@Test
@DirtiesContext
public void testRefresh() throws Exception {
assertEquals("Hello scope!", service.getMessage());
String id1 = service.toString();
// Change the dynamic property source...
properties.setMessage("Foo");
// ...and then refresh, so the bean is re-initialized:
scope.refreshAll();
String id2 = service.toString();
assertEquals("Foo", service.getMessage());
assertEquals(2, ExampleService.getInitCount());
assertEquals(1, ExampleService.getDestroyCount());
assertNotSame(id1, id2);
assertNotNull(ExampleService.event);
assertEquals(RefreshScopeRefreshedEvent.DEFAULT_NAME,
ExampleService.event.getName());
}
@Test
@DirtiesContext
public void testRefreshBean() throws Exception {
assertEquals("Hello scope!", service.getMessage());
String id1 = service.toString();
// Change the dynamic property source...
properties.setMessage("Foo");
// ...and then refresh, so the bean is re-initialized:
scope.refresh("service");
String id2 = service.toString();
assertEquals("Foo", service.getMessage());
assertEquals(2, ExampleService.getInitCount());
assertEquals(1, ExampleService.getDestroyCount());
assertNotSame(id1, id2);
assertNotNull(ExampleService.event);
assertEquals(GenericScope.SCOPED_TARGET_PREFIX + "service",
ExampleService.event.getName());
}
public static interface Service {
String getMessage();
}
public static class ExampleService implements Service, InitializingBean,
DisposableBean, ApplicationListener<RefreshScopeRefreshedEvent> {
private static Log logger = LogFactory.getLog(ExampleService.class);
private volatile static int initCount = 0;
private volatile static int destroyCount = 0;
private volatile static RefreshScopeRefreshedEvent event;
private String message = null;
private volatile long delay = 0;
public void setDelay(long delay) {
this.delay = delay;
}
public void afterPropertiesSet() throws Exception {
logger.debug("Initializing message: " + message);
initCount++;
}
public void destroy() throws Exception {
logger.debug("Destroying message: " + message);
destroyCount++;
message = null;
}
public static void reset() {
initCount = 0;
destroyCount = 0;
event = null;
}
public static int getInitCount() {
return initCount;
}
public static int getDestroyCount() {
return destroyCount;
}
public void setMessage(String message) {
logger.debug("Setting message: " + message);
this.message = message;
}
public String getMessage() {
logger.debug("Getting message: " + message);
try {
Thread.sleep(delay);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
logger.info("Returning message: " + message);
return message;
}
@Override
public void onApplicationEvent(RefreshScopeRefreshedEvent e) {
event = e;
}
}
@Configuration
@EnableConfigurationProperties(TestProperties.class)
@Import({ RefreshAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected static class TestConfiguration {
@Autowired
private TestProperties properties;
@Bean
@RefreshScope
public ExampleService service() {
ExampleService service = new ExampleService();
service.setMessage(properties.getMessage());
service.setDelay(properties.getDelay());
return service;
}
}
@ConfigurationProperties
@ManagedResource
protected static class TestProperties {
private String message;
private int delay;
@ManagedAttribute
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@ManagedAttribute
public int getDelay() {
return delay;
}
public void setDelay(int delay) {
this.delay = delay;
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2013-2014 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.context.scope.refresh;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.environment.EnvironmentManager;
import org.springframework.cloud.context.scope.refresh.RefreshScopeWebIntegrationTests.Application;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Dave Syer
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class RefreshScopeWebIntegrationTests {
@Autowired
private org.springframework.cloud.context.scope.refresh.RefreshScope scope;
@Autowired
private EnvironmentManager environmentManager;
@Autowired
private Client application;
@Autowired
private ConfigurableListableBeanFactory beanFactory;
@Test
public void scopeOnBeanDefinition() throws Exception {
assertEquals("refresh", beanFactory.getBeanDefinition("scopedTarget.application").getScope());
}
@Test
public void beanAccess() throws Exception {
application.hello();
environmentManager.setProperty("message", "Hello Dave!");
scope.refreshAll();
String message = application.hello();
assertEquals("Hello Dave!", message);
}
@Configuration
@EnableAutoConfiguration
protected static class Application {
@Bean
@RefreshScope
public Client application() {
return new Client();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
protected static class Client {
@Value("${message:Hello World!}")
String message;
@RequestMapping("/")
public String hello() {
return message;
}
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2013-2014 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.logging;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import org.junit.After;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
/**
* @author Dave Syer
*
*/
public class LoggingRebinderTests {
private LoggingRebinder rebinder = new LoggingRebinder();
private Logger logger = LoggerFactory.getLogger("org.springframework.web");
@After
public void reset() {
LoggingSystem.get(getClass().getClassLoader()).setLogLevel("org.springframework.web", LogLevel.INFO);
}
@Test
public void logLevelsChanged() {
assertFalse(logger.isTraceEnabled());
StandardEnvironment environment = new StandardEnvironment();
EnvironmentTestUtils.addEnvironment(environment, "logging.level.org.springframework.web=TRACE");
rebinder.setEnvironment(environment);
rebinder.onApplicationEvent(new EnvironmentChangeEvent(Collections.singleton("logging.level.org.springframework.web")));
assertTrue(logger.isTraceEnabled());
}
}