Support Retry in spring.config.import=configserver:
Fixes gh-1775
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import org.springframework.boot.BootstrapRegistry;
|
||||
import org.springframework.boot.Bootstrapper;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.cloud.config.client.ConfigServerBootstrapper.LoaderInterceptor;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Bootstrapper.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public class ConfigClientRetryBootstrapper implements Bootstrapper {
|
||||
|
||||
static final boolean RETRY_IS_PRESENT = ClassUtils.isPresent("org.springframework.retry.annotation.Retryable",
|
||||
null);
|
||||
|
||||
@Override
|
||||
public void intitialize(BootstrapRegistry registry) {
|
||||
if (!RETRY_IS_PRESENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
registry.registerIfAbsent(RetryProperties.class, context -> context.get(Binder.class)
|
||||
.bind(RetryProperties.PREFIX, RetryProperties.class).orElseGet(RetryProperties::new));
|
||||
|
||||
registry.registerIfAbsent(RetryTemplate.class, context -> {
|
||||
RetryProperties properties = context.get(RetryProperties.class);
|
||||
return RetryTemplate.builder().maxAttempts(properties.getMaxAttempts()).exponentialBackoff(
|
||||
properties.getInitialInterval(), properties.getMultiplier(), properties.getMaxInterval()).build();
|
||||
});
|
||||
registry.registerIfAbsent(LoaderInterceptor.class, context -> {
|
||||
Binder binder = context.get(Binder.class);
|
||||
boolean failFast = binder.bind(ConfigClientProperties.PREFIX + ".fail-fast", Boolean.class).orElse(false);
|
||||
if (failFast) {
|
||||
// if (false) {
|
||||
RetryTemplate retryTemplate = context.get(RetryTemplate.class);
|
||||
return loadContext -> retryTemplate.execute(retryContext -> loadContext.getInvocation()
|
||||
.apply(loadContext.getLoaderContext(), loadContext.getResource()));
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -78,8 +78,10 @@ public class ConfigServerConfigDataLoader implements ConfigDataLoader<ConfigServ
|
||||
}
|
||||
if (context.getBootstrapContext().isRegistered(LoaderInterceptor.class)) {
|
||||
LoaderInterceptor interceptor = context.getBootstrapContext().get(LoaderInterceptor.class);
|
||||
Binder binder = context.getBootstrapContext().get(Binder.class);
|
||||
return interceptor.apply(new LoadContext(context, resource, binder, this::doLoad));
|
||||
if (interceptor != null) {
|
||||
Binder binder = context.getBootstrapContext().get(Binder.class);
|
||||
return interceptor.apply(new LoadContext(context, resource, binder, this::doLoad));
|
||||
}
|
||||
}
|
||||
return doLoad(context, resource);
|
||||
}
|
||||
|
||||
@@ -35,8 +35,11 @@ import org.springframework.boot.context.config.Profiles;
|
||||
import org.springframework.boot.context.properties.bind.BindHandler;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@@ -150,13 +153,32 @@ public class ConfigServerConfigDataLocationResolver
|
||||
.bind(CONFIG_DISCOVERY_ENABLED, Bindable.of(Boolean.class), getBindHandler(resolverContext))
|
||||
.orElse(false);
|
||||
|
||||
boolean retryEnabled = resolverContext.getBinder().bind(ConfigClientProperties.PREFIX + ".fail-fast",
|
||||
Bindable.of(Boolean.class), getBindHandler(resolverContext)).orElse(false);
|
||||
|
||||
if (discoveryEnabled) {
|
||||
log.debug(LogMessage.format("discovery enabled"));
|
||||
// register ConfigServerInstanceMonitor
|
||||
bootstrapContext.registerIfAbsent(ConfigServerInstanceMonitor.class, context -> {
|
||||
ConfigServerInstanceProvider.Function function = context
|
||||
.get(ConfigServerInstanceProvider.Function.class);
|
||||
ConfigServerInstanceProvider instanceProvider = new ConfigServerInstanceProvider(function);
|
||||
|
||||
ConfigServerInstanceProvider instanceProvider;
|
||||
if (ConfigClientRetryBootstrapper.RETRY_IS_PRESENT && retryEnabled) {
|
||||
log.debug(LogMessage.format("discovery plus retry enabled"));
|
||||
RetryTemplate retryTemplate = context.get(RetryTemplate.class);
|
||||
instanceProvider = new ConfigServerInstanceProvider(function) {
|
||||
@Override
|
||||
public List<ServiceInstance> getConfigServerInstances(String serviceId) {
|
||||
return retryTemplate.execute(retryContext -> super.getConfigServerInstances(serviceId));
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
instanceProvider = new ConfigServerInstanceProvider(function);
|
||||
}
|
||||
instanceProvider.setLog(log);
|
||||
|
||||
ConfigClientProperties clientProperties = context.get(ConfigClientProperties.class);
|
||||
ConfigServerInstanceMonitor instanceMonitor = new ConfigServerInstanceMonitor(log, clientProperties,
|
||||
instanceProvider);
|
||||
|
||||
@@ -56,8 +56,7 @@ public class ConfigServiceBootstrapConfiguration {
|
||||
@ConditionalOnMissingBean(ConfigServicePropertySourceLocator.class)
|
||||
@ConditionalOnProperty(name = ConfigClientProperties.PREFIX + ".enabled", matchIfMissing = true)
|
||||
public ConfigServicePropertySourceLocator configServicePropertySource(ConfigClientProperties properties) {
|
||||
ConfigServicePropertySourceLocator locator = new ConfigServicePropertySourceLocator(properties);
|
||||
return locator;
|
||||
return new ConfigServicePropertySourceLocator(properties);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(ConfigClientProperties.PREFIX + ".fail-fast")
|
||||
|
||||
@@ -22,9 +22,14 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.config.retry")
|
||||
@ConfigurationProperties(RetryProperties.PREFIX)
|
||||
public class RetryProperties {
|
||||
|
||||
/**
|
||||
* ConfigurationProperties prefix.
|
||||
*/
|
||||
public static final String PREFIX = "spring.cloud.config.retry";
|
||||
|
||||
/**
|
||||
* Initial retry interval in milliseconds.
|
||||
*/
|
||||
|
||||
@@ -13,3 +13,7 @@ org.springframework.cloud.config.client.ConfigServerConfigDataLocationResolver
|
||||
# ConfigData Loaders
|
||||
org.springframework.boot.context.config.ConfigDataLoader=\
|
||||
org.springframework.cloud.config.client.ConfigServerConfigDataLoader
|
||||
|
||||
# Spring Boot Bootstrappers
|
||||
org.springframework.boot.Bootstrapper=\
|
||||
org.springframework.cloud.config.client.ConfigClientRetryBootstrapper
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.boot.BootstrapRegistry;
|
||||
import org.springframework.boot.Bootstrapper;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.config.client.ConfigClientProperties.Credentials;
|
||||
import org.springframework.cloud.test.ClassPathExclusions;
|
||||
import org.springframework.cloud.test.ModifiedClassPathRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.cloud.config.client.ConfigClientProperties.Discovery.DEFAULT_CONFIG_SERVER;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions({ "spring-retry-*.jar", "spring-boot-starter-aop-*.jar" })
|
||||
public class DiscoveryClientConfigDataConfigurationNoRetryTests {
|
||||
|
||||
protected ConfigurableApplicationContext context;
|
||||
|
||||
protected DiscoveryClient client = Mockito.mock(DiscoveryClient.class);
|
||||
|
||||
protected ServiceInstance info = new DefaultServiceInstance("app:8877", "app", "foo", 8877, false);
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailWithExceptionGetConfigServerInstanceFromDiscoveryClient() throws Exception {
|
||||
givenDiscoveryClientReturnsNoInfo();
|
||||
|
||||
assertThatThrownBy(() -> context = setup("spring.cloud.config.discovery.enabled=true",
|
||||
"spring.cloud.config.fail-fast=true").run()).isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("No instances found of configserver");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailWithMessageGetConfigServerInstanceFromDiscoveryClient() throws Exception {
|
||||
givenDiscoveryClientReturnsNoInfo();
|
||||
|
||||
context = setup("spring.cloud.config.discovery.enabled=true", "spring.cloud.config.fail-fast=false").run();
|
||||
|
||||
// expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
|
||||
expectConfigClientPropertiesHasDefaultConfiguration();
|
||||
verifyDiscoveryClientCalledOnce();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSucceedGetConfigServerInstanceFromDiscoveryClient() throws Exception {
|
||||
givenDiscoveryClientReturnsInfo();
|
||||
|
||||
context = setup("spring.cloud.config.discovery.enabled=true", "spring.cloud.config.fail-fast=true").run();
|
||||
|
||||
// expectDiscoveryClientConfigServiceBootstrapConfigurationIsSetup();
|
||||
// expectConfigClientPropertiesHasConfigurationFromEureka();
|
||||
verifyDiscoveryClientCalledOnce();
|
||||
}
|
||||
|
||||
SpringApplicationBuilder setup(String... env) {
|
||||
return setup(true, env);
|
||||
}
|
||||
|
||||
SpringApplicationBuilder setup(boolean addInstanceProvider, String... env) {
|
||||
SpringApplicationBuilder builder = new SpringApplicationBuilder(TestConfig.class)
|
||||
.properties(addDefaultEnv(env));
|
||||
if (addInstanceProvider) {
|
||||
builder.addBootstrapper(instanceProviderBootstrapper());
|
||||
// ignore actual calls to config server since we're just testing discovery
|
||||
// client.
|
||||
builder.addBootstrapper(registry -> registry.register(ConfigServerBootstrapper.LoaderInterceptor.class,
|
||||
ctx -> loadContext -> null));
|
||||
}
|
||||
return builder.addBootstrapper(registry -> registry.addCloseListener(event -> {
|
||||
ConfigServerInstanceMonitor monitor = event.getBootstrapContext().get(ConfigServerInstanceMonitor.class);
|
||||
assertThat(monitor).as("ConfigServerInstanceMonitor was not created when it should").isNotNull();
|
||||
}));
|
||||
}
|
||||
|
||||
protected Bootstrapper instanceProviderBootstrapper() {
|
||||
return registry -> registry.register(ConfigServerInstanceProvider.Function.class,
|
||||
BootstrapRegistry.InstanceSupplier.from(() -> this.client::getInstances));
|
||||
}
|
||||
|
||||
private String[] addDefaultEnv(String[] env) {
|
||||
Set<String> set = new LinkedHashSet<>();
|
||||
if (env != null && env.length > 0) {
|
||||
set.addAll(Arrays.asList(env));
|
||||
}
|
||||
set.add("spring.cloud.config.discovery.enabled=true");
|
||||
set.add("spring.config.import=optional:configserver:");
|
||||
return set.toArray(new String[0]);
|
||||
}
|
||||
|
||||
void givenDiscoveryClientReturnsInfo() {
|
||||
givenDiscoveryClientReturnsInfo(this.info);
|
||||
}
|
||||
|
||||
void givenDiscoveryClientReturnsInfo(ServiceInstance... instances) {
|
||||
given(this.client.getInstances(DEFAULT_CONFIG_SERVER)).willReturn(Arrays.asList(instances));
|
||||
}
|
||||
|
||||
void givenDiscoveryClientReturnsNoInfo() {
|
||||
given(this.client.getInstances(DEFAULT_CONFIG_SERVER)).willReturn(Collections.emptyList());
|
||||
}
|
||||
|
||||
void verifyDiscoveryClientCalledOnce() {
|
||||
verify(this.client).getInstances(DEFAULT_CONFIG_SERVER);
|
||||
}
|
||||
|
||||
void expectConfigClientPropertiesHasDefaultConfiguration() {
|
||||
expectConfigClientPropertiesHasConfiguration("http://localhost:8888");
|
||||
}
|
||||
|
||||
void expectConfigClientPropertiesHasConfiguration(final String expectedUri) {
|
||||
ConfigClientProperties properties = this.context.getBean(ConfigClientProperties.class);
|
||||
Credentials credentials = properties.getCredentials(0);
|
||||
assertThat(credentials.getUri()).isEqualTo(expectedUri);
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
static class TestConfig {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@@ -39,6 +38,7 @@ import org.springframework.cloud.config.client.ConfigClientProperties.Credential
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -164,7 +164,6 @@ public class DiscoveryClientConfigDataConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void shouldRetryAndSucceedGetConfigServerInstanceFromDiscoveryClient() {
|
||||
givenDiscoveryClientReturnsInfoOnThirdTry();
|
||||
|
||||
@@ -179,7 +178,6 @@ public class DiscoveryClientConfigDataConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void shouldNotRetryIfNotFailFastPropertySet() {
|
||||
givenDiscoveryClientReturnsInfoOnThirdTry();
|
||||
|
||||
@@ -191,18 +189,16 @@ public class DiscoveryClientConfigDataConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void shouldRetryAndFailWithExceptionGetConfigServerInstanceFromDiscoveryClient() {
|
||||
givenDiscoveryClientReturnsNoInfo();
|
||||
|
||||
// expectNoInstancesOfConfigServerException();
|
||||
|
||||
context = setup("spring.cloud.config.retry.maxAttempts=3", "spring.cloud.config.retry.initialInterval=10",
|
||||
"spring.cloud.config.fail-fast=true").run();
|
||||
assertThatThrownBy(() -> context = setup("spring.cloud.config.retry.maxAttempts=3",
|
||||
"spring.cloud.config.retry.initialInterval=10", "spring.cloud.config.fail-fast=true").run())
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("No instances found of configserver");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void shouldRetryAndFailWithMessageGetConfigServerInstanceFromDiscoveryClient() {
|
||||
givenDiscoveryClientReturnsNoInfo();
|
||||
|
||||
@@ -221,6 +217,10 @@ public class DiscoveryClientConfigDataConfigurationTests {
|
||||
.properties(addDefaultEnv(env));
|
||||
if (addInstanceProvider) {
|
||||
builder.addBootstrapper(instanceProviderBootstrapper());
|
||||
// ignore actual calls to config server since we're just testing discovery
|
||||
// client.
|
||||
builder.addBootstrapper(registry -> registry.register(ConfigServerBootstrapper.LoaderInterceptor.class,
|
||||
ctx -> loadContext -> null));
|
||||
}
|
||||
return builder.addBootstrapper(registry -> registry.addCloseListener(event -> {
|
||||
ConfigServerInstanceMonitor monitor = event.getBootstrapContext().get(ConfigServerInstanceMonitor.class);
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -20,22 +20,27 @@ import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
public class ApplicationFailFastTests {
|
||||
|
||||
@Test
|
||||
public void contextFails() {
|
||||
try {
|
||||
public void bootstrapContextFails() {
|
||||
assertThatThrownBy(() -> {
|
||||
new SpringApplicationBuilder().sources(Application.class).run("--spring.config.use-legacy-processing=true",
|
||||
"--server.port=0", "--spring.cloud.config.enabled=true", "--spring.cloud.config.fail-fast=true",
|
||||
"--spring.cloud.config.uri=http://serverhostdoesnotexist:1234");
|
||||
fail("failFast option did not produce an exception");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e.getMessage().contains("fail fast")).as("Exception not caused by fail fast").isTrue();
|
||||
}
|
||||
}).as("Exception not caused by fail fast").hasMessageContaining("fail fast");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configDataContextFails() {
|
||||
assertThatThrownBy(() -> {
|
||||
new SpringApplicationBuilder().sources(Application.class).run("--server.port=0",
|
||||
"--spring.cloud.config.enabled=true", "--spring.cloud.config.fail-fast=true",
|
||||
"--spring.config.import=optional:configserver:http://serverhostdoesnotexist:1234");
|
||||
}).as("Exception not caused by fail fast").hasMessageContaining("fail fast");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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 sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.config.server.EnableConfigServer;
|
||||
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.SocketUtils;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Application.class,
|
||||
// Normally spring.cloud.config.enabled:true is the default but since we have the
|
||||
// config server on the classpath we need to set it explicitly
|
||||
properties = { "spring.application.name=retryapp", "spring.cloud.config.fail-fast=true",
|
||||
"spring.cloud.config.enabled=true", "spring.config.import=configserver:",
|
||||
"management.security.enabled=false", "management.endpoints.web.exposure.include=*",
|
||||
"logging.level.org.springframework.retry=TRACE" },
|
||||
webEnvironment = RANDOM_PORT)
|
||||
public class ConfigDataRetryIntegrationTests {
|
||||
|
||||
private static final String BASE_PATH = new WebEndpointProperties().getBasePath();
|
||||
|
||||
private static int configPort = SocketUtils.findAvailableTcpPort();
|
||||
|
||||
private static ConfigurableApplicationContext server;
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@BeforeClass
|
||||
public static void startConfigServer() throws IOException {
|
||||
String baseDir = ConfigServerTestUtils.getBaseDirectory("spring-cloud-config-sample");
|
||||
String repo = ConfigServerTestUtils.prepareLocalRepo(baseDir, "target/repos", "config-repo", "target/config");
|
||||
server = SpringApplication.run(TestConfig.class, "--server.port=" + configPort, "--spring.config.name=server",
|
||||
"--spring.cloud.config.server.git.uri=" + repo);
|
||||
|
||||
System.setProperty("spring.cloud.config.uri", "http://localhost:" + configPort);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void close() {
|
||||
System.clearProperty("spring.cloud.config.uri");
|
||||
if (server != null) {
|
||||
server.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void contextLoads() {
|
||||
Map res = new TestRestTemplate().getForObject("http://localhost:" + this.port + BASE_PATH + "/env/info.foo",
|
||||
Map.class);
|
||||
assertThat(res).containsKey("propertySources");
|
||||
Map<String, Object> property = (Map<String, Object>) res.get("property");
|
||||
assertThat(property).containsEntry("value", "bar");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableConfigServer
|
||||
static class TestConfig implements WebMvcConfigurer {
|
||||
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
|
||||
// @Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new HandlerInterceptor() {
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
if (request.getServletPath().equals("/retryapp/default")) {
|
||||
return count.incrementAndGet() > 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user