Merge branch 'master' of https://github.com/spring-cloud/spring-cloud-netflix into zuul_hystrix_threadpool
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -16,3 +16,5 @@ _site/
|
||||
.factorypath
|
||||
*.log
|
||||
.shelf
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<properties>
|
||||
<docs.main>spring-cloud-netflix</docs.main>
|
||||
<main.basedir>${basedir}/..</main.basedir>
|
||||
<docs.whitelisted.branches>1.0.x,1.1.x</docs.whitelisted.branches>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@@ -12,43 +12,118 @@ if ! [ -d docs/target/generated-docs ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Find name of current branch
|
||||
# The script should be executed from the root folder
|
||||
|
||||
ROOT_FOLDER=`pwd`
|
||||
echo "Current folder is ${ROOT_FOLDER}"
|
||||
|
||||
if [[ ! -e "${ROOT_FOLDER}/.git" ]]; then
|
||||
echo "You're not in the root folder of the project!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Retrieve properties
|
||||
###################################################################
|
||||
branch=$TRAVIS_BRANCH
|
||||
[ "$branch" == "" ] && branch=`git rev-parse --abbrev-ref HEAD`
|
||||
target=.
|
||||
if [ "$branch" != "master" ]; then target=./$branch; mkdir -p $target; fi
|
||||
|
||||
# Prop that will let commit the changes
|
||||
COMMIT_CHANGES="no"
|
||||
MAVEN_PATH=${MAVEN_PATH:-}
|
||||
echo "Path to Maven is [${MAVEN_PATH}]"
|
||||
|
||||
# Code getting the name of the current branch. For master we want to publish as we did until now
|
||||
# http://stackoverflow.com/questions/1593051/how-to-programmatically-determine-the-current-checked-out-git-branch
|
||||
# If there is a branch already passed will reuse it - otherwise will try to find it
|
||||
CURRENT_BRANCH=${BRANCH}
|
||||
if [[ -z "${CURRENT_BRANCH}" ]] ; then
|
||||
CURRENT_BRANCH=$(git symbolic-ref -q HEAD)
|
||||
CURRENT_BRANCH=${CURRENT_BRANCH##refs/heads/}
|
||||
CURRENT_BRANCH=${CURRENT_BRANCH:-HEAD}
|
||||
fi
|
||||
echo "Current branch is [${CURRENT_BRANCH}]"
|
||||
git checkout ${CURRENT_BRANCH}
|
||||
|
||||
# Get the name of the `docs.main` property
|
||||
MAIN_ADOC_VALUE=$("${MAVEN_PATH}"mvn -q \
|
||||
-Dexec.executable="echo" \
|
||||
-Dexec.args='${docs.main}' \
|
||||
--non-recursive \
|
||||
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec)
|
||||
echo "Extracted 'main.adoc' from Maven build [${MAIN_ADOC_VALUE}]"
|
||||
|
||||
# Get whitelisted branches - assumes that a `docs` module is available under `docs` profile
|
||||
WHITELIST_PROPERTY="docs.whitelisted.branches"
|
||||
WHITELISTED_BRANCHES_VALUE=$("${MAVEN_PATH}"mvn -q \
|
||||
-Dexec.executable="echo" \
|
||||
-Dexec.args="\${${WHITELIST_PROPERTY}}" \
|
||||
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
|
||||
-P docs \
|
||||
-pl docs)
|
||||
echo "Extracted '${WHITELIST_PROPERTY}' from Maven build [${WHITELISTED_BRANCHES_VALUE}]"
|
||||
|
||||
# Stash any outstanding changes
|
||||
###################################################################
|
||||
git diff-index --quiet HEAD
|
||||
dirty=$?
|
||||
git diff-index --quiet HEAD && dirty=$? || (echo "Failed to check if the current repo is dirty. Assuming that it is." && dirty="1")
|
||||
if [ "$dirty" != "0" ]; then git stash; fi
|
||||
|
||||
# Switch to gh-pages branch to sync it with current branch
|
||||
# Switch to gh-pages branch to sync it with master
|
||||
###################################################################
|
||||
git checkout gh-pages
|
||||
git pull origin gh-pages
|
||||
|
||||
for f in docs/target/generated-docs/*; do
|
||||
file=${f#docs/target/generated-docs/*}
|
||||
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
|
||||
# Not ignored...
|
||||
cp -rf $f $target
|
||||
git add -A $target/$file
|
||||
fi
|
||||
done
|
||||
|
||||
git add -A README.adoc || echo "No change to README.adoc"
|
||||
git commit -a -m "Sync docs from $branch to gh-pages" || echo "Nothing committed"
|
||||
|
||||
# Uncomment the following push if you want to auto push to
|
||||
# the gh-pages branch whenever you commit to branch locally.
|
||||
# This is a little extreme. Use with care!
|
||||
# Add git branches
|
||||
###################################################################
|
||||
git push origin gh-pages || echo "Cannot push gh-pages"
|
||||
mkdir -p ${ROOT_FOLDER}/${CURRENT_BRANCH}
|
||||
if [[ "${CURRENT_BRANCH}" == "master" ]] ; then
|
||||
echo -e "Current branch is master - will copy the current docs only to the root folder"
|
||||
for f in docs/target/generated-docs/*; do
|
||||
file=${f#docs/target/generated-docs/*}
|
||||
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
|
||||
# Not ignored...
|
||||
cp -rf $f ${ROOT_FOLDER}/
|
||||
git add -A ${ROOT_FOLDER}/$file
|
||||
fi
|
||||
done
|
||||
COMMIT_CHANGES="yes"
|
||||
else
|
||||
echo -e "Current branch is [${CURRENT_BRANCH}]"
|
||||
# http://stackoverflow.com/questions/29300806/a-bash-script-to-check-if-a-string-is-present-in-a-comma-separated-list-of-strin
|
||||
if [[ ",${WHITELISTED_BRANCHES_VALUE}," = *",${CURRENT_BRANCH},"* ]] ; then
|
||||
echo -e "Branch [${CURRENT_BRANCH}] is whitelisted! Will copy the current docs to the [${CURRENT_BRANCH}] folder"
|
||||
for f in docs/target/generated-docs/*; do
|
||||
file=${f#docs/target/generated-docs/*}
|
||||
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
|
||||
# Not ignored...
|
||||
# We want users to access 1.0.0.RELEASE/ instead of 1.0.0.RELEASE/spring-cloud.sleuth.html
|
||||
if [[ "${file}" == "${MAIN_ADOC_VALUE}.html" ]] ; then
|
||||
# We don't want to copy the spring-cloud-sleuth.html
|
||||
# we want it to be converted to index.html
|
||||
cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html
|
||||
git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html
|
||||
else
|
||||
cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH}
|
||||
git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/$file
|
||||
fi
|
||||
fi
|
||||
done
|
||||
COMMIT_CHANGES="yes"
|
||||
else
|
||||
echo -e "Branch [${CURRENT_BRANCH}] is not on the white list! Check out the Maven [${WHITELIST_PROPERTY}] property in
|
||||
[docs] module available under [docs] profile. Won't commit any changes to gh-pages for this branch."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Finally, switch back to the current branch and exit block
|
||||
git checkout $branch
|
||||
if [[ "${COMMIT_CHANGES}" == "yes" ]] ; then
|
||||
git commit -a -m "Sync docs from ${CURRENT_BRANCH} to gh-pages"
|
||||
|
||||
# Uncomment the following push if you want to auto push to
|
||||
# the gh-pages branch whenever you commit to master locally.
|
||||
# This is a little extreme. Use with care!
|
||||
###################################################################
|
||||
git push origin gh-pages
|
||||
fi
|
||||
|
||||
# Finally, switch back to the master branch and exit block
|
||||
git checkout ${CURRENT_BRANCH}
|
||||
if [ "$dirty" != "0" ]; then git stash pop; fi
|
||||
|
||||
exit 0
|
||||
exit 0
|
||||
@@ -14,9 +14,9 @@ curl "${SCRIPT_URL}" --output runAcceptanceTests.sh
|
||||
chmod +x runAcceptanceTests.sh
|
||||
|
||||
echo "Killing all running apps"
|
||||
./runAcceptanceTests.sh -t "${AT_WHAT_TO_TEST}" -n
|
||||
./runAcceptanceTests.sh -t "${AT_WHAT_TO_TEST}" --killnow
|
||||
|
||||
./runAcceptanceTests.sh -t "${AT_WHAT_TO_TEST}" -k
|
||||
./runAcceptanceTests.sh -t "${AT_WHAT_TO_TEST}" --killattheend
|
||||
|
||||
SCRIPT_URL="https://raw.githubusercontent.com/spring-cloud-samples/tests/master/scripts/runTests.sh"
|
||||
|
||||
|
||||
@@ -82,6 +82,11 @@ public class ZuulProperties {
|
||||
*/
|
||||
private boolean addProxyHeaders = true;
|
||||
|
||||
/**
|
||||
* Flag to determine whether the proxy forwards the Host header.
|
||||
*/
|
||||
private boolean addHostHeader = false;
|
||||
|
||||
/**
|
||||
* Set of service names not to consider for proxying automatically. By default all
|
||||
* services in the discovery client will be proxied.
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.springframework.cloud.netflix.zuul.filters.pre;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
|
||||
import org.springframework.cloud.netflix.zuul.filters.Route;
|
||||
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
|
||||
@@ -36,6 +38,8 @@ import lombok.extern.apachecommons.CommonsLog;
|
||||
@CommonsLog
|
||||
public class PreDecorationFilter extends ZuulFilter {
|
||||
|
||||
public static final int FILTER_ORDER = 5;
|
||||
|
||||
private RouteLocator routeLocator;
|
||||
|
||||
private String dispatcherServletPath;
|
||||
@@ -58,7 +62,7 @@ public class PreDecorationFilter extends ZuulFilter {
|
||||
|
||||
@Override
|
||||
public int filterOrder() {
|
||||
return 5;
|
||||
return FILTER_ORDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -115,29 +119,34 @@ public class PreDecorationFilter extends ZuulFilter {
|
||||
ctx.addOriginResponseHeader("X-Zuul-ServiceId", location);
|
||||
}
|
||||
if (this.properties.isAddProxyHeaders()) {
|
||||
ctx.addZuulRequestHeader("X-Forwarded-Host",
|
||||
ctx.getRequest().getServerName());
|
||||
ctx.addZuulRequestHeader("X-Forwarded-Host", toHostHeader(ctx.getRequest()));
|
||||
ctx.addZuulRequestHeader("X-Forwarded-Port",
|
||||
String.valueOf(ctx.getRequest().getServerPort()));
|
||||
ctx.addZuulRequestHeader(ZuulHeaders.X_FORWARDED_PROTO,
|
||||
ctx.getRequest().getScheme());
|
||||
String forwardedPrefix =
|
||||
ctx.getRequest().getHeader("X-Forwarded-Prefix");
|
||||
String contextPath = ctx.getRequest().getContextPath();
|
||||
String prefix = StringUtils.hasLength(forwardedPrefix)
|
||||
? forwardedPrefix
|
||||
: (StringUtils.hasLength(contextPath) ? contextPath : null);
|
||||
if (StringUtils.hasText(route.getPrefix())) {
|
||||
String existingPrefix = ctx.getRequest()
|
||||
.getHeader("X-Forwarded-Prefix");
|
||||
StringBuilder newPrefixBuilder = new StringBuilder();
|
||||
if (StringUtils.hasLength(existingPrefix)) {
|
||||
if (existingPrefix.endsWith("/")
|
||||
if (prefix != null) {
|
||||
if (prefix.endsWith("/")
|
||||
&& route.getPrefix().startsWith("/")) {
|
||||
newPrefixBuilder.append(existingPrefix, 0,
|
||||
existingPrefix.length() - 1);
|
||||
newPrefixBuilder.append(prefix, 0,
|
||||
prefix.length() - 1);
|
||||
}
|
||||
else {
|
||||
newPrefixBuilder.append(existingPrefix);
|
||||
newPrefixBuilder.append(prefix);
|
||||
}
|
||||
}
|
||||
newPrefixBuilder.append(route.getPrefix());
|
||||
ctx.addZuulRequestHeader("X-Forwarded-Prefix",
|
||||
newPrefixBuilder.toString());
|
||||
prefix = newPrefixBuilder.toString();
|
||||
}
|
||||
if (prefix != null) {
|
||||
ctx.addZuulRequestHeader("X-Forwarded-Prefix", prefix);
|
||||
}
|
||||
String xforwardedfor = ctx.getRequest().getHeader("X-Forwarded-For");
|
||||
String remoteAddr = ctx.getRequest().getRemoteAddr();
|
||||
@@ -149,6 +158,9 @@ public class PreDecorationFilter extends ZuulFilter {
|
||||
}
|
||||
ctx.addZuulRequestHeader("X-Forwarded-For", xforwardedfor);
|
||||
}
|
||||
if (this.properties.isAddHostHeader()) {
|
||||
ctx.addZuulRequestHeader("Host", toHostHeader(ctx.getRequest()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -182,6 +194,15 @@ public class PreDecorationFilter extends ZuulFilter {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String toHostHeader(HttpServletRequest request) {
|
||||
int port = request.getServerPort();
|
||||
if ((port == 80 && "http".equals(request.getScheme())) || (port == 443 && "https".equals(request.getScheme()))) {
|
||||
return request.getServerName();
|
||||
} else {
|
||||
return request.getServerName() + ":" + port;
|
||||
}
|
||||
}
|
||||
|
||||
private URL getUrl(String target) {
|
||||
try {
|
||||
return new URL(target);
|
||||
|
||||
@@ -1,290 +1,289 @@
|
||||
package org.springframework.cloud.netflix.resttemplate;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
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.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.netflix.client.RetryHandler;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.AvailabilityFilteringRule;
|
||||
import com.netflix.loadbalancer.BaseLoadBalancer;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.IPing;
|
||||
import com.netflix.loadbalancer.IRule;
|
||||
import com.netflix.loadbalancer.LoadBalancerBuilder;
|
||||
import com.netflix.loadbalancer.LoadBalancerStats;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
import com.netflix.loadbalancer.ServerStats;
|
||||
import com.netflix.niws.client.http.HttpClientLoadBalancerErrorHandler;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = RestTemplateRetryTest.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
|
||||
"spring.application.name=resttemplatetest",
|
||||
"logging.level.org.springframework.cloud.netflix.resttemplate=DEBUG",
|
||||
"badClients.ribbon.MaxAutoRetries=0",
|
||||
"badClients.ribbon.OkToRetryOnAllOperations=true", "ribbon.http.client.enabled" })
|
||||
@DirtiesContext
|
||||
public class RestTemplateRetryTest {
|
||||
|
||||
final private static Log logger = LogFactory.getLog(RestTemplateRetryTest.class);
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port = 0;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate testClient;
|
||||
|
||||
public RestTemplateRetryTest() {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
@RibbonClient(name = "badClients", configuration = LocalBadClientConfiguration.class)
|
||||
public static class Application {
|
||||
|
||||
private AtomicInteger hits = new AtomicInteger(1);
|
||||
private AtomicInteger retryHits = new AtomicInteger(1);
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/ping")
|
||||
public int ping() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/good")
|
||||
public int good() {
|
||||
int lValue = this.hits.getAndIncrement();
|
||||
return lValue;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/timeout")
|
||||
public int timeout() throws Exception {
|
||||
int lValue = this.retryHits.getAndIncrement();
|
||||
|
||||
// Force the good server to have 2 consecutive errors a couple of times.
|
||||
if (lValue == 2 || lValue == 3 || lValue == 5 || lValue == 6) {
|
||||
Thread.sleep(500);
|
||||
}
|
||||
return lValue;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/null")
|
||||
public int isNull() throws Exception {
|
||||
throw new NullPointerException("Null");
|
||||
}
|
||||
|
||||
@LoadBalanced
|
||||
@Bean
|
||||
RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
// Force Ribbon configuration by making one call.
|
||||
this.testClient.getForObject("http://badClients/ping", Integer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullPointer() throws Exception {
|
||||
|
||||
LoadBalancerStats stats = LocalBadClientConfiguration.balancer
|
||||
.getLoadBalancerStats();
|
||||
ServerStats badServer1Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer);
|
||||
ServerStats badServer2Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer2);
|
||||
ServerStats goodServerStats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
badServer1Stats.clearSuccessiveConnectionFailureCount();
|
||||
badServer2Stats.clearSuccessiveConnectionFailureCount();
|
||||
long targetConnectionCount = goodServerStats.getTotalRequestsCount() + 10;
|
||||
|
||||
// A null pointer should NOT trigger a circuit breaker.
|
||||
for (int index = 0; index < 10; index++) {
|
||||
try {
|
||||
this.testClient.getForObject("http://badClients/null", Integer.class);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
}
|
||||
}
|
||||
logServerStats(LocalBadClientConfiguration.badServer);
|
||||
logServerStats(LocalBadClientConfiguration.badServer2);
|
||||
logServerStats(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
assertTrue(badServer1Stats.isCircuitBreakerTripped());
|
||||
assertTrue(badServer2Stats.isCircuitBreakerTripped());
|
||||
assertEquals(targetConnectionCount, goodServerStats.getTotalRequestsCount());
|
||||
|
||||
// Wait for any timeout thread to finish.
|
||||
|
||||
}
|
||||
|
||||
private void logServerStats(Server server) {
|
||||
LoadBalancerStats stats = LocalBadClientConfiguration.balancer
|
||||
.getLoadBalancerStats();
|
||||
ServerStats serverStats = stats.getSingleServerStat(server);
|
||||
logger.debug("Server : " + server.toString() + " : Total Count == "
|
||||
+ serverStats.getTotalRequestsCount() + ", Failure Count == "
|
||||
+ serverStats.getFailureCount() + ", Successive Connection Failure == "
|
||||
+ serverStats.getSuccessiveConnectionFailureCount()
|
||||
+ ", Circuit Breaker ? == " + serverStats.isCircuitBreakerTripped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestRetries() {
|
||||
|
||||
LoadBalancerStats stats = LocalBadClientConfiguration.balancer
|
||||
.getLoadBalancerStats();
|
||||
ServerStats badServer1Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer);
|
||||
ServerStats badServer2Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer2);
|
||||
ServerStats goodServerStats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
badServer1Stats.clearSuccessiveConnectionFailureCount();
|
||||
badServer2Stats.clearSuccessiveConnectionFailureCount();
|
||||
long targetConnectionCount = goodServerStats.getTotalRequestsCount() + 20;
|
||||
|
||||
int hits = 0;
|
||||
|
||||
for (int index = 0; index < 20; index++) {
|
||||
hits = this.testClient.getForObject("http://badClients/good", Integer.class);
|
||||
}
|
||||
|
||||
logServerStats(LocalBadClientConfiguration.badServer);
|
||||
logServerStats(LocalBadClientConfiguration.badServer2);
|
||||
logServerStats(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
assertTrue(badServer1Stats.isCircuitBreakerTripped());
|
||||
assertTrue(badServer2Stats.isCircuitBreakerTripped());
|
||||
assertEquals(targetConnectionCount, goodServerStats.getTotalRequestsCount());
|
||||
assertEquals(20, hits);
|
||||
System.out.println("Retry Hits: " + hits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestRetriesWithReadTimeout() throws Exception {
|
||||
|
||||
LoadBalancerStats stats = LocalBadClientConfiguration.balancer
|
||||
.getLoadBalancerStats();
|
||||
ServerStats badServer1Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer);
|
||||
ServerStats badServer2Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer2);
|
||||
ServerStats goodServerStats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
badServer1Stats.clearSuccessiveConnectionFailureCount();
|
||||
badServer2Stats.clearSuccessiveConnectionFailureCount();
|
||||
assertTrue(!badServer1Stats.isCircuitBreakerTripped());
|
||||
assertTrue(!badServer2Stats.isCircuitBreakerTripped());
|
||||
|
||||
int hits = 0;
|
||||
|
||||
for (int index = 0; index < 15; index++) {
|
||||
hits = this.testClient.getForObject("http://badClients/timeout",
|
||||
Integer.class);
|
||||
}
|
||||
logServerStats(LocalBadClientConfiguration.badServer);
|
||||
logServerStats(LocalBadClientConfiguration.badServer2);
|
||||
logServerStats(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
assertTrue(badServer1Stats.isCircuitBreakerTripped());
|
||||
assertTrue(badServer2Stats.isCircuitBreakerTripped());
|
||||
assertTrue(!goodServerStats.isCircuitBreakerTripped());
|
||||
|
||||
// 15 + 4 timeouts. See the endpoint for timeout conditions.
|
||||
assertEquals(19, hits);
|
||||
|
||||
// Wait for any timeout thread to finish.
|
||||
Thread.sleep(600);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Load balancer with fixed server list for "local" pointing to localhost
|
||||
// and some bogus servers are thrown in to test retry
|
||||
@Configuration
|
||||
class LocalBadClientConfiguration {
|
||||
|
||||
static BaseLoadBalancer balancer;
|
||||
static Server goodServer;
|
||||
static Server badServer;
|
||||
static Server badServer2;
|
||||
|
||||
public LocalBadClientConfiguration() {
|
||||
}
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port = 0;
|
||||
|
||||
@Bean
|
||||
public IRule loadBalancerRule() {
|
||||
// This is a good place to try different load balancing rules and how those rules
|
||||
// behave in failure
|
||||
// states: BestAvailableRule, WeightedResponseTimeRule, etc
|
||||
|
||||
// This rule just uses a round robin and will skip servers that are in circuit
|
||||
// breaker state.
|
||||
return new AvailabilityFilteringRule();
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
|
||||
ServerList<Server> serverList, IRule rule, IPing ping) {
|
||||
|
||||
goodServer = new Server("localhost", this.port);
|
||||
badServer = new Server("mybadhost", 10001);
|
||||
badServer2 = new Server("localhost", -1);
|
||||
|
||||
balancer = LoadBalancerBuilder.newBuilder().withClientConfig(config)
|
||||
.withRule(rule).withPing(ping).buildFixedServerListLoadBalancer(
|
||||
Arrays.asList(badServer, badServer2, goodServer));
|
||||
return balancer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RetryHandler retryHandler() {
|
||||
return new OverrideRetryHandler();
|
||||
}
|
||||
|
||||
static class OverrideRetryHandler extends HttpClientLoadBalancerErrorHandler {
|
||||
public OverrideRetryHandler() {
|
||||
this.circuitRelated.add(UnknownHostException.class);
|
||||
this.retriable.add(UnknownHostException.class);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package org.springframework.cloud.netflix.resttemplate;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
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.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.SocketUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.netflix.client.RetryHandler;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.AvailabilityFilteringRule;
|
||||
import com.netflix.loadbalancer.BaseLoadBalancer;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.IPing;
|
||||
import com.netflix.loadbalancer.IRule;
|
||||
import com.netflix.loadbalancer.LoadBalancerBuilder;
|
||||
import com.netflix.loadbalancer.LoadBalancerStats;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
import com.netflix.loadbalancer.ServerStats;
|
||||
import com.netflix.niws.client.http.HttpClientLoadBalancerErrorHandler;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = RestTemplateRetryTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
|
||||
"spring.application.name=resttemplatetest",
|
||||
"logging.level.org.springframework.cloud.netflix.resttemplate=DEBUG",
|
||||
"logging.level.com.netflix=DEBUG", "badClients.ribbon.MaxAutoRetries=0",
|
||||
"badClients.ribbon.OkToRetryOnAllOperations=true", "ribbon.http.client.enabled" })
|
||||
@DirtiesContext
|
||||
public class RestTemplateRetryTests {
|
||||
|
||||
final private static Log logger = LogFactory.getLog(RestTemplateRetryTests.class);
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port = 0;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate testClient;
|
||||
|
||||
public RestTemplateRetryTests() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
// Force Ribbon configuration by making one call.
|
||||
this.testClient.getForObject("http://badClients/ping", Integer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullPointer() throws Exception {
|
||||
|
||||
LoadBalancerStats stats = LocalBadClientConfiguration.balancer
|
||||
.getLoadBalancerStats();
|
||||
ServerStats badServer1Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer);
|
||||
ServerStats badServer2Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer2);
|
||||
ServerStats goodServerStats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
badServer1Stats.clearSuccessiveConnectionFailureCount();
|
||||
badServer2Stats.clearSuccessiveConnectionFailureCount();
|
||||
long targetConnectionCount = goodServerStats.getTotalRequestsCount() + 10;
|
||||
|
||||
// A null pointer should NOT trigger a circuit breaker.
|
||||
for (int index = 0; index < 10; index++) {
|
||||
try {
|
||||
this.testClient.getForObject("http://badClients/null", Integer.class);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
}
|
||||
}
|
||||
logServerStats(LocalBadClientConfiguration.badServer);
|
||||
logServerStats(LocalBadClientConfiguration.badServer2);
|
||||
logServerStats(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
assertTrue(badServer1Stats.isCircuitBreakerTripped());
|
||||
assertTrue(badServer2Stats.isCircuitBreakerTripped());
|
||||
assertEquals(targetConnectionCount, goodServerStats.getTotalRequestsCount());
|
||||
|
||||
// Wait for any timeout thread to finish.
|
||||
|
||||
}
|
||||
|
||||
private void logServerStats(Server server) {
|
||||
LoadBalancerStats stats = LocalBadClientConfiguration.balancer
|
||||
.getLoadBalancerStats();
|
||||
ServerStats serverStats = stats.getSingleServerStat(server);
|
||||
logger.debug("Server : " + server.toString() + " : Total Count == "
|
||||
+ serverStats.getTotalRequestsCount() + ", Failure Count == "
|
||||
+ serverStats.getFailureCount() + ", Successive Connection Failure == "
|
||||
+ serverStats.getSuccessiveConnectionFailureCount()
|
||||
+ ", Circuit Breaker ? == " + serverStats.isCircuitBreakerTripped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestRetries() {
|
||||
|
||||
LoadBalancerStats stats = LocalBadClientConfiguration.balancer
|
||||
.getLoadBalancerStats();
|
||||
ServerStats badServer1Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer);
|
||||
ServerStats badServer2Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer2);
|
||||
ServerStats goodServerStats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
badServer1Stats.clearSuccessiveConnectionFailureCount();
|
||||
badServer2Stats.clearSuccessiveConnectionFailureCount();
|
||||
long targetConnectionCount = goodServerStats.getTotalRequestsCount() + 20;
|
||||
|
||||
int hits = 0;
|
||||
|
||||
for (int index = 0; index < 20; index++) {
|
||||
hits = this.testClient.getForObject("http://badClients/good", Integer.class);
|
||||
}
|
||||
|
||||
logServerStats(LocalBadClientConfiguration.badServer);
|
||||
logServerStats(LocalBadClientConfiguration.badServer2);
|
||||
logServerStats(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
assertTrue(badServer1Stats.isCircuitBreakerTripped());
|
||||
assertTrue(badServer2Stats.isCircuitBreakerTripped());
|
||||
assertEquals(targetConnectionCount, goodServerStats.getTotalRequestsCount());
|
||||
assertEquals(20, hits);
|
||||
logger.debug("Retry Hits: " + hits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestRetriesWithReadTimeout() throws Exception {
|
||||
|
||||
LoadBalancerStats stats = LocalBadClientConfiguration.balancer
|
||||
.getLoadBalancerStats();
|
||||
ServerStats badServer1Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer);
|
||||
ServerStats badServer2Stats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.badServer2);
|
||||
ServerStats goodServerStats = stats
|
||||
.getSingleServerStat(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
badServer1Stats.clearSuccessiveConnectionFailureCount();
|
||||
badServer2Stats.clearSuccessiveConnectionFailureCount();
|
||||
assertTrue(!badServer1Stats.isCircuitBreakerTripped());
|
||||
assertTrue(!badServer2Stats.isCircuitBreakerTripped());
|
||||
|
||||
int hits = 0;
|
||||
|
||||
for (int index = 0; index < 15; index++) {
|
||||
hits = this.testClient.getForObject("http://badClients/timeout",
|
||||
Integer.class);
|
||||
}
|
||||
logServerStats(LocalBadClientConfiguration.badServer);
|
||||
logServerStats(LocalBadClientConfiguration.badServer2);
|
||||
logServerStats(LocalBadClientConfiguration.goodServer);
|
||||
|
||||
assertTrue(badServer1Stats.isCircuitBreakerTripped());
|
||||
assertTrue(badServer2Stats.isCircuitBreakerTripped());
|
||||
assertTrue(!goodServerStats.isCircuitBreakerTripped());
|
||||
|
||||
// 15 + 4 timeouts. See the endpoint for timeout conditions.
|
||||
assertEquals(19, hits);
|
||||
|
||||
// Wait for any timeout thread to finish.
|
||||
Thread.sleep(600);
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
@RibbonClient(name = "badClients", configuration = LocalBadClientConfiguration.class)
|
||||
public static class Application {
|
||||
|
||||
private AtomicInteger hits = new AtomicInteger(1);
|
||||
private AtomicInteger retryHits = new AtomicInteger(1);
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/ping")
|
||||
public int ping() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/good")
|
||||
public int good() {
|
||||
int lValue = this.hits.getAndIncrement();
|
||||
return lValue;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/timeout")
|
||||
public int timeout() throws Exception {
|
||||
int lValue = this.retryHits.getAndIncrement();
|
||||
|
||||
// Force the good server to have 2 consecutive errors a couple of times.
|
||||
if (lValue == 2 || lValue == 3 || lValue == 5 || lValue == 6) {
|
||||
Thread.sleep(500);
|
||||
}
|
||||
return lValue;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/null")
|
||||
public int isNull() throws Exception {
|
||||
throw new NullPointerException("Null");
|
||||
}
|
||||
|
||||
@LoadBalanced
|
||||
@Bean
|
||||
RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Load balancer with fixed server list for "local" pointing to localhost
|
||||
// and some bogus servers are thrown in to test retry
|
||||
@Configuration
|
||||
class LocalBadClientConfiguration {
|
||||
|
||||
static BaseLoadBalancer balancer;
|
||||
static Server goodServer;
|
||||
static Server badServer;
|
||||
static Server badServer2;
|
||||
|
||||
public LocalBadClientConfiguration() {
|
||||
}
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port = 0;
|
||||
|
||||
@Bean
|
||||
public IRule loadBalancerRule() {
|
||||
// This is a good place to try different load balancing rules and how those rules
|
||||
// behave in failure states: BestAvailableRule, WeightedResponseTimeRule, etc
|
||||
|
||||
// This rule just uses a round robin and will skip servers that are in circuit
|
||||
// breaker state.
|
||||
return new AvailabilityFilteringRule();
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
|
||||
ServerList<Server> serverList, IRule rule, IPing ping) {
|
||||
|
||||
goodServer = new Server("localhost", this.port);
|
||||
badServer = new Server("mybadhost", 10001);
|
||||
badServer2 = new Server("localhost", SocketUtils.findAvailableTcpPort());
|
||||
|
||||
balancer = LoadBalancerBuilder.newBuilder().withClientConfig(config)
|
||||
.withRule(rule).withPing(ping).buildFixedServerListLoadBalancer(
|
||||
Arrays.asList(badServer, badServer2, goodServer));
|
||||
return balancer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RetryHandler retryHandler() {
|
||||
return new OverrideRetryHandler();
|
||||
}
|
||||
|
||||
static class OverrideRetryHandler extends HttpClientLoadBalancerErrorHandler {
|
||||
public OverrideRetryHandler() {
|
||||
this.circuitRelated.add(UnknownHostException.class);
|
||||
this.retriable.add(UnknownHostException.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -90,6 +90,34 @@ public class PreDecorationFilterTests {
|
||||
assertEquals(false, this.filter.shouldFilter());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xForwardedHostHasPort() throws Exception {
|
||||
this.properties.setPrefix("/api");
|
||||
this.request.setRequestURI("/api/foo/1");
|
||||
this.request.setRemoteAddr("5.6.7.8");
|
||||
this.request.setServerPort(8080);
|
||||
this.routeLocator.addRoute(
|
||||
new ZuulRoute("foo", "/foo/**", "foo", null, false, null, null));
|
||||
this.filter.run();
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
assertEquals("localhost:8080", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostHeaderSet() throws Exception {
|
||||
this.properties.setPrefix("/api");
|
||||
this.properties.setAddHostHeader(true);
|
||||
this.request.setRequestURI("/api/foo/1");
|
||||
this.request.setRemoteAddr("5.6.7.8");
|
||||
this.request.setServerPort(8080);
|
||||
this.routeLocator.addRoute(
|
||||
new ZuulRoute("foo", "/foo/**", "foo", null, false, null, null));
|
||||
this.filter.run();
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
assertEquals("localhost:8080", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
|
||||
assertEquals("localhost:8080", ctx.getZuulRequestHeaders().get("host"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prefixRouteAddsHeader() throws Exception {
|
||||
this.properties.setPrefix("/api");
|
||||
@@ -136,6 +164,86 @@ public class PreDecorationFilterTests {
|
||||
getHeader(ctx.getOriginResponseHeaders(), "x-zuul-serviceid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void routeWithContextPath() {
|
||||
this.properties.setStripPrefix(false);
|
||||
this.request.setRequestURI("/api/foo/1");
|
||||
this.request.setContextPath("/context-path");
|
||||
this.routeLocator.addRoute(
|
||||
new ZuulRoute("foo", "/api/foo/**", "foo", null, false, null, null));
|
||||
this.filter.run();
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
assertEquals("/api/foo/1", ctx.get("requestURI"));
|
||||
assertEquals("localhost", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
|
||||
assertEquals("80", ctx.getZuulRequestHeaders().get("x-forwarded-port"));
|
||||
assertEquals("http", ctx.getZuulRequestHeaders().get("x-forwarded-proto"));
|
||||
assertEquals("/context-path",
|
||||
ctx.getZuulRequestHeaders().get("x-forwarded-prefix"));
|
||||
assertEquals("foo",
|
||||
getHeader(ctx.getOriginResponseHeaders(), "x-zuul-serviceid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prefixRouteWithContextPath() {
|
||||
this.properties.setPrefix("/api");
|
||||
this.properties.setStripPrefix(true);
|
||||
this.request.setRequestURI("/api/foo/1");
|
||||
this.request.setContextPath("/context-path");
|
||||
this.routeLocator.addRoute(
|
||||
new ZuulRoute("foo", "/foo/**", "foo", null, false, null, null));
|
||||
this.filter.run();
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
assertEquals("/foo/1", ctx.get("requestURI"));
|
||||
assertEquals("localhost", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
|
||||
assertEquals("80", ctx.getZuulRequestHeaders().get("x-forwarded-port"));
|
||||
assertEquals("http", ctx.getZuulRequestHeaders().get("x-forwarded-proto"));
|
||||
assertEquals("/context-path/api",
|
||||
ctx.getZuulRequestHeaders().get("x-forwarded-prefix"));
|
||||
assertEquals("foo",
|
||||
getHeader(ctx.getOriginResponseHeaders(), "x-zuul-serviceid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void routeIgnoreContextPathIfPrefixHeader() {
|
||||
this.properties.setStripPrefix(false);
|
||||
this.request.setRequestURI("/api/foo/1");
|
||||
this.request.setContextPath("/context-path");
|
||||
this.request.addHeader("X-Forwarded-Prefix", "/prefix");
|
||||
this.routeLocator.addRoute(
|
||||
new ZuulRoute("foo", "/api/foo/**", "foo", null, false, null, null));
|
||||
this.filter.run();
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
assertEquals("/api/foo/1", ctx.get("requestURI"));
|
||||
assertEquals("localhost", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
|
||||
assertEquals("80", ctx.getZuulRequestHeaders().get("x-forwarded-port"));
|
||||
assertEquals("http", ctx.getZuulRequestHeaders().get("x-forwarded-proto"));
|
||||
assertEquals("/prefix",
|
||||
ctx.getZuulRequestHeaders().get("x-forwarded-prefix"));
|
||||
assertEquals("foo",
|
||||
getHeader(ctx.getOriginResponseHeaders(), "x-zuul-serviceid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prefixRouteIgnoreContextPathIfPrefixHeader() {
|
||||
this.properties.setPrefix("/api");
|
||||
this.properties.setStripPrefix(true);
|
||||
this.request.setRequestURI("/api/foo/1");
|
||||
this.request.setContextPath("/context-path");
|
||||
this.request.addHeader("X-Forwarded-Prefix", "/prefix");
|
||||
this.routeLocator.addRoute(
|
||||
new ZuulRoute("foo", "/foo/**", "foo", null, false, null, null));
|
||||
this.filter.run();
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
assertEquals("/foo/1", ctx.get("requestURI"));
|
||||
assertEquals("localhost", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
|
||||
assertEquals("80", ctx.getZuulRequestHeaders().get("x-forwarded-port"));
|
||||
assertEquals("http", ctx.getZuulRequestHeaders().get("x-forwarded-proto"));
|
||||
assertEquals("/prefix/api",
|
||||
ctx.getZuulRequestHeaders().get("x-forwarded-prefix"));
|
||||
assertEquals("foo",
|
||||
getHeader(ctx.getOriginResponseHeaders(), "x-zuul-serviceid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forwardRouteAddsLocation() throws Exception {
|
||||
this.properties.setPrefix("/api");
|
||||
@@ -377,7 +485,7 @@ public class PreDecorationFilterTests {
|
||||
assertTrue("sensitiveHeaders is wrong: " + sensitiveHeaders,
|
||||
sensitiveHeaders.containsAll(Arrays.asList("x-bar", "x-foo")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void urlProperlyDecodedWhenCharacterEncodingIsSet() throws Exception {
|
||||
this.request.setCharacterEncoding("UTF-8");
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
@@ -204,7 +203,8 @@ public class EurekaClientAutoConfiguration {
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Conditional(OnRefreshScopeCondition.class)
|
||||
@ConditionalOnClass(RefreshScope.class)
|
||||
@ConditionalOnBean(RefreshAutoConfiguration.class)
|
||||
@interface ConditionalOnRefreshScope {
|
||||
|
||||
}
|
||||
@@ -219,24 +219,10 @@ public class EurekaClientAutoConfiguration {
|
||||
static class MissingClass {
|
||||
}
|
||||
|
||||
@ConditionalOnClass(RefreshScope.class)
|
||||
@ConditionalOnMissingBean(RefreshAutoConfiguration.class)
|
||||
static class MissingScope {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class OnRefreshScopeCondition extends AllNestedConditions {
|
||||
|
||||
public OnRefreshScopeCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnClass(RefreshScope.class)
|
||||
@ConditionalOnBean(RefreshAutoConfiguration.class)
|
||||
static class FoundScope {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -112,8 +112,8 @@ public class EurekaClientAutoConfigurationTests {
|
||||
EnvironmentTestUtils.addEnvironment(this.context, "server.port=8989",
|
||||
"eureka.client.serviceUrl.defaultZone=http://user:foo@example.com:80/eureka");
|
||||
setupContext(MockClientConfiguration.class);
|
||||
//ApacheHttpClient4 http = this.context.getBean(ApacheHttpClient4.class);
|
||||
//Mockito.verify(http).addFilter(Matchers.any(HTTPBasicAuthFilter.class));
|
||||
// ApacheHttpClient4 http = this.context.getBean(ApacheHttpClient4.class);
|
||||
// Mockito.verify(http).addFilter(Matchers.any(HTTPBasicAuthFilter.class));
|
||||
}
|
||||
|
||||
private void testNonSecurePort(String propName) {
|
||||
|
||||
Reference in New Issue
Block a user