Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
spring-cloud-netflix
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
openSource
spring-cloud-netflix
Commits
384c9b97
Commit
384c9b97
authored
Feb 15, 2017
by
Ryan Baxter
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://github.com/spring-cloud/spring-cloud-netflix
parents
981fa5db
c417a9a5
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
359 additions
and
45 deletions
+359
-45
spring-cloud-netflix.adoc
docs/src/main/asciidoc/spring-cloud-netflix.adoc
+51
-0
HystrixTargeter.java
.../springframework/cloud/netflix/feign/HystrixTargeter.java
+14
-1
SpringMvcContract.java
...mework/cloud/netflix/feign/support/SpringMvcContract.java
+1
-4
RibbonUtils.java
...org/springframework/cloud/netflix/ribbon/RibbonUtils.java
+1
-1
SendResponseFilter.java
...k/cloud/netflix/zuul/filters/post/SendResponseFilter.java
+17
-11
FormBodyWrapperFilter.java
...cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java
+8
-3
RibbonRoutingFilter.java
...cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java
+1
-0
SimpleHostRoutingFilter.java
...d/netflix/zuul/filters/route/SimpleHostRoutingFilter.java
+10
-8
AbstractRibbonCommandFactory.java
...l/filters/route/support/AbstractRibbonCommandFactory.java
+12
-2
SpringMvcContractTests.java
...k/cloud/netflix/feign/support/SpringMvcContractTests.java
+18
-0
FeignClientTests.java
...framework/cloud/netflix/feign/valid/FeignClientTests.java
+72
-10
RibbonUtilsTests.java
...pringframework/cloud/netflix/ribbon/RibbonUtilsTests.java
+8
-0
SendResponseFilterTests.java
...ud/netflix/zuul/filters/post/SendResponseFilterTests.java
+40
-0
HttpClientRibbonCommandFallbackTests.java
...rs/route/apache/HttpClientRibbonCommandFallbackTests.java
+1
-1
OkHttpRibbonCommandFallbackTests.java
...ilters/route/okhttp/OkHttpRibbonCommandFallbackTests.java
+1
-1
RestClientRibbonCommandFallbackTests.java
...oute/restclient/RestClientRibbonCommandFallbackTests.java
+1
-1
RibbonCommandFallbackTests.java
...uul/filters/route/support/RibbonCommandFallbackTests.java
+103
-2
No files found.
docs/src/main/asciidoc/spring-cloud-netflix.adoc
View file @
384c9b97
...
...
@@ -976,6 +976,7 @@ Spring Cloud Netflix _does not_ provide the following beans by default for feign
*
`
ErrorDecoder
`
*
`
Request
.
Options
`
*
`
Collection
<
RequestInterceptor
>`
*
`
SetterFactory
`
Creating
a
bean
of
one
of
those
type
and
placing
it
in
a
`@
FeignClient
`
configuration
(
such
as
`
FooConfiguration
`
above
)
allows
you
to
override
each
one
of
the
beans
described
.
Example
:
...
...
@@ -1768,6 +1769,56 @@ zuul:
customers
:
/
customers
/**
----
If
you
would
like
to
provide
a
default
fallback
for
all
routes
than
you
can
create
a
bean
of
type
`
ZuulFallbackProvider
`
and
have
the
`
getRoute
`
method
return
`*`
or
`
null
`.
[
source
,
java
]
----
class
MyFallbackProvider
implements
ZuulFallbackProvider
{
@
Override
public
String
getRoute
()
{
return
"*"
;
}
@
Override
public
ClientHttpResponse
fallbackResponse
()
{
return
new
ClientHttpResponse
()
{
@
Override
public
HttpStatus
getStatusCode
()
throws
IOException
{
return
HttpStatus
.
OK
;
}
@
Override
public
int
getRawStatusCode
()
throws
IOException
{
return
200
;
}
@
Override
public
String
getStatusText
()
throws
IOException
{
return
"OK"
;
}
@
Override
public
void
close
()
{
}
@
Override
public
InputStream
getBody
()
throws
IOException
{
return
new
ByteArrayInputStream
(
"fallback"
.
getBytes
());
}
@
Override
public
HttpHeaders
getHeaders
()
{
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_JSON
);
return
headers
;
}
};
}
}
----
[[
zuul
-
developer
-
guide
]]
===
Zuul
Developer
Guide
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/HystrixTargeter.java
View file @
384c9b97
...
...
@@ -17,14 +17,17 @@
package
org
.
springframework
.
cloud
.
netflix
.
feign
;
import
org.springframework.util.Assert
;
import
feign.Feign
;
import
feign.Target
;
import
feign.hystrix.FallbackFactory
;
import
feign.hystrix.HystrixFeign
;
import
org.springframework.util.Assert
;
import
feign.hystrix.SetterFactory
;
/**
* @author Spencer Gibb
* @author Erik Kringen
*/
@SuppressWarnings
(
"unchecked"
)
class
HystrixTargeter
implements
Targeter
{
...
...
@@ -36,6 +39,11 @@ class HystrixTargeter implements Targeter {
return
feign
.
target
(
target
);
}
feign
.
hystrix
.
HystrixFeign
.
Builder
builder
=
(
feign
.
hystrix
.
HystrixFeign
.
Builder
)
feign
;
SetterFactory
setterFactory
=
getOptional
(
factory
.
getName
(),
context
,
SetterFactory
.
class
);
if
(
setterFactory
!=
null
)
{
builder
.
setterFactory
(
setterFactory
);
}
Class
<?>
fallback
=
factory
.
getFallback
();
if
(
fallback
!=
void
.
class
)
{
return
targetWithFallback
(
factory
.
getName
(),
context
,
target
,
builder
,
fallback
);
...
...
@@ -95,4 +103,9 @@ class HystrixTargeter implements Targeter {
}
return
(
T
)
fallbackInstance
;
}
private
<
T
>
T
getOptional
(
String
feignClientName
,
FeignContext
context
,
Class
<
T
>
beanType
)
{
return
context
.
getInstance
(
feignClientName
,
beanType
);
}
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringMvcContract.java
View file @
384c9b97
...
...
@@ -28,7 +28,6 @@ import java.util.LinkedHashMap;
import
java.util.List
;
import
java.util.Map
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor
;
import
org.springframework.cloud.netflix.feign.annotation.PathVariableParameterProcessor
;
import
org.springframework.cloud.netflix.feign.annotation.RequestHeaderParameterProcessor
;
...
...
@@ -324,9 +323,7 @@ public class SpringMvcContract extends Contract.BaseContract
// has a parameter name
return
parameterNames
!=
null
&&
parameterNames
.
length
>
parameterIndex
// has a type
&&
parameterTypes
!=
null
&&
parameterTypes
.
length
>
parameterIndex
// and it is a simple property
&&
BeanUtils
.
isSimpleProperty
(
parameterTypes
[
parameterIndex
].
getClass
());
&&
parameterTypes
!=
null
&&
parameterTypes
.
length
>
parameterIndex
;
}
private
class
SimpleAnnotatedParameterContext
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonUtils.java
View file @
384c9b97
...
...
@@ -71,7 +71,7 @@ public class RibbonUtils {
public
static
URI
updateToHttpsIfNeeded
(
URI
uri
,
IClientConfig
config
,
ServerIntrospector
serverIntrospector
,
Server
server
)
{
String
scheme
=
uri
.
getScheme
();
if
(!
"https"
.
equals
(
scheme
)
&&
isSecure
(
config
,
serverIntrospector
,
server
))
{
if
(!
"
"
.
equals
(
uri
.
toString
())
&&
!
"
https"
.
equals
(
scheme
)
&&
isSecure
(
config
,
serverIntrospector
,
server
))
{
UriComponentsBuilder
uriComponentsBuilder
=
UriComponentsBuilder
.
fromUri
(
uri
).
scheme
(
"https"
);
if
(
uri
.
getRawQuery
()
!=
null
)
{
// When building the URI, UriComponentsBuilder verify the allowed characters and does not
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/post/SendResponseFilter.java
View file @
384c9b97
...
...
@@ -17,6 +17,7 @@
package
org
.
springframework
.
cloud
.
netflix
.
zuul
.
filters
.
post
;
import
java.io.ByteArrayInputStream
;
import
java.io.Closeable
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
...
...
@@ -184,28 +185,33 @@ public class SendResponseFilter extends ZuulFilter {
}
}
finally
{
/**
* Closing the wrapping InputStream itself has no effect on closing the underlying tcp connection since it's a wrapped stream. I guess for http
* keep-alive. When closing the wrapping stream it tries to reach the end of the current request, which is impossible for infinite http streams. So
* instead of closing the InputStream we close the HTTP response.
*
* @author Johannes Edmeier
*/
try
{
if
(
is
!=
null
)
{
is
.
close
();
Object
zuulResponse
=
RequestContext
.
getCurrentContext
()
.
get
(
"zuulResponse"
);
if
(
zuulResponse
instanceof
Closeable
)
{
((
Closeable
)
zuulResponse
).
close
();
}
outStream
.
flush
();
// The container will close the stream for us
}
catch
(
IOException
ex
)
{
log
.
warn
(
"Error while sending response to client: "
+
ex
.
getMessage
());
}
}
}
private
void
writeResponse
(
InputStream
zin
,
OutputStream
out
)
throws
Exception
{
try
{
byte
[]
bytes
=
buffers
.
get
();
int
bytesRead
=
-
1
;
while
((
bytesRead
=
zin
.
read
(
bytes
))
!=
-
1
)
{
out
.
write
(
bytes
,
0
,
bytesRead
);
}
}
catch
(
IOException
ioe
)
{
log
.
warn
(
"Error while sending response to client: "
+
ioe
.
getMessage
());
byte
[]
bytes
=
buffers
.
get
();
int
bytesRead
=
-
1
;
while
((
bytesRead
=
zin
.
read
(
bytes
))
!=
-
1
)
{
out
.
write
(
bytes
,
0
,
bytesRead
);
}
}
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java
View file @
384c9b97
...
...
@@ -31,6 +31,7 @@ import org.springframework.http.HttpHeaders;
import
org.springframework.http.HttpOutputMessage
;
import
org.springframework.http.InvalidMediaTypeException
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.converter.FormHttpMessageConverter
;
import
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
;
import
org.springframework.util.Assert
;
import
org.springframework.util.MultiValueMap
;
...
...
@@ -52,10 +53,16 @@ import static org.springframework.cloud.netflix.zuul.filters.support.FilterConst
*/
public
class
FormBodyWrapperFilter
extends
ZuulFilter
{
private
FormHttpMessageConverter
formHttpMessageConverter
;
private
Field
requestField
;
private
Field
servletRequestField
;
public
FormBodyWrapperFilter
()
{
this
(
new
AllEncompassingFormHttpMessageConverter
());
}
public
FormBodyWrapperFilter
(
FormHttpMessageConverter
formHttpMessageConverter
)
{
this
.
formHttpMessageConverter
=
formHttpMessageConverter
;
this
.
requestField
=
ReflectionUtils
.
findField
(
HttpServletRequestWrapper
.
class
,
"req"
,
HttpServletRequest
.
class
);
this
.
servletRequestField
=
ReflectionUtils
.
findField
(
ServletRequestWrapper
.
class
,
...
...
@@ -139,8 +146,6 @@ public class FormBodyWrapperFilter extends ZuulFilter {
private
int
contentLength
;
private
AllEncompassingFormHttpMessageConverter
converter
=
new
AllEncompassingFormHttpMessageConverter
();
public
FormBodyRequestWrapper
(
HttpServletRequest
request
)
{
super
(
request
);
this
.
request
=
request
;
...
...
@@ -184,7 +189,7 @@ public class FormBodyWrapperFilter extends ZuulFilter {
this
.
contentType
=
MediaType
.
valueOf
(
this
.
request
.
getContentType
());
data
.
getHeaders
().
setContentType
(
this
.
contentType
);
this
.
c
onverter
.
write
(
builder
,
this
.
contentType
,
data
);
FormBodyWrapperFilter
.
this
.
formHttpMessageC
onverter
.
write
(
builder
,
this
.
contentType
,
data
);
// copy new content type including multipart boundary
this
.
contentType
=
data
.
getHeaders
().
getContentType
();
this
.
contentData
=
data
.
getInput
();
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java
View file @
384c9b97
...
...
@@ -218,6 +218,7 @@ public class RibbonRoutingFilter extends ZuulFilter {
protected
void
setResponse
(
ClientHttpResponse
resp
)
throws
ClientException
,
IOException
{
RequestContext
.
getCurrentContext
().
set
(
"zuulResponse"
,
resp
);
this
.
helper
.
setResponse
(
resp
.
getStatusCode
().
value
(),
resp
.
getBody
()
==
null
?
null
:
resp
.
getBody
(),
resp
.
getHeaders
());
}
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java
View file @
384c9b97
...
...
@@ -42,10 +42,10 @@ import org.apache.http.HttpHost;
import
org.apache.http.HttpRequest
;
import
org.apache.http.HttpResponse
;
import
org.apache.http.ProtocolException
;
import
org.apache.http.client.HttpClient
;
import
org.apache.http.client.RedirectStrategy
;
import
org.apache.http.client.config.CookieSpecs
;
import
org.apache.http.client.config.RequestConfig
;
import
org.apache.http.client.methods.CloseableHttpResponse
;
import
org.apache.http.client.methods.HttpPatch
;
import
org.apache.http.client.methods.HttpPost
;
import
org.apache.http.client.methods.HttpPut
;
...
...
@@ -192,8 +192,8 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
this
.
helper
.
addIgnoredHeaders
();
try
{
HttpResponse
response
=
forward
(
this
.
httpClient
,
verb
,
uri
,
request
,
headers
,
params
,
requestEntity
);
CloseableHttpResponse
response
=
forward
(
this
.
httpClient
,
verb
,
uri
,
request
,
headers
,
params
,
requestEntity
);
setResponse
(
response
);
}
catch
(
Exception
ex
)
{
...
...
@@ -278,8 +278,8 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
}).
build
();
}
private
HttpResponse
forward
(
HttpClient
httpclient
,
String
verb
,
String
uri
,
HttpServletRequest
request
,
MultiValueMap
<
String
,
String
>
headers
,
private
CloseableHttpResponse
forward
(
CloseableHttpClient
httpclient
,
String
verb
,
String
uri
,
HttpServletRequest
request
,
MultiValueMap
<
String
,
String
>
headers
,
MultiValueMap
<
String
,
String
>
params
,
InputStream
requestEntity
)
throws
Exception
{
Map
<
String
,
Object
>
info
=
this
.
helper
.
debug
(
verb
,
uri
,
headers
,
params
,
...
...
@@ -301,7 +301,8 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
try
{
log
.
debug
(
httpHost
.
getHostName
()
+
" "
+
httpHost
.
getPort
()
+
" "
+
httpHost
.
getSchemeName
());
HttpResponse
zuulResponse
=
forwardRequest
(
httpclient
,
httpHost
,
httpRequest
);
CloseableHttpResponse
zuulResponse
=
forwardRequest
(
httpclient
,
httpHost
,
httpRequest
);
this
.
helper
.
appendDebug
(
info
,
zuulResponse
.
getStatusLine
().
getStatusCode
(),
revertHeaders
(
zuulResponse
.
getAllHeaders
()));
return
zuulResponse
;
...
...
@@ -379,8 +380,8 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
return
list
.
toArray
(
new
BasicHeader
[
0
]);
}
private
HttpResponse
forwardRequest
(
HttpClient
httpclient
,
HttpHost
httpHos
t
,
HttpRequest
httpRequest
)
throws
IOException
{
private
CloseableHttpResponse
forwardRequest
(
CloseableHttpClient
httpclien
t
,
Http
Host
httpHost
,
Http
Request
httpRequest
)
throws
IOException
{
return
httpclient
.
execute
(
httpHost
,
httpRequest
);
}
...
...
@@ -407,6 +408,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
}
private
void
setResponse
(
HttpResponse
response
)
throws
IOException
{
RequestContext
.
getCurrentContext
().
set
(
"zuulResponse"
,
response
);
this
.
helper
.
setResponse
(
response
.
getStatusLine
().
getStatusCode
(),
response
.
getEntity
()
==
null
?
null
:
response
.
getEntity
().
getContent
(),
revertHeaders
(
response
.
getAllHeaders
()));
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/support/AbstractRibbonCommandFactory.java
View file @
384c9b97
...
...
@@ -30,15 +30,25 @@ import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider
public
abstract
class
AbstractRibbonCommandFactory
implements
RibbonCommandFactory
{
private
Map
<
String
,
ZuulFallbackProvider
>
fallbackProviderCache
;
private
ZuulFallbackProvider
defaultFallbackProvider
=
null
;
public
AbstractRibbonCommandFactory
(
Set
<
ZuulFallbackProvider
>
fallbackProviders
){
this
.
fallbackProviderCache
=
new
HashMap
<>();
for
(
ZuulFallbackProvider
provider
:
fallbackProviders
)
{
fallbackProviderCache
.
put
(
provider
.
getRoute
(),
provider
);
String
route
=
provider
.
getRoute
();
if
(
"*"
.
equals
(
route
)
||
route
==
null
)
{
defaultFallbackProvider
=
provider
;
}
else
{
fallbackProviderCache
.
put
(
route
,
provider
);
}
}
}
protected
ZuulFallbackProvider
getFallbackProvider
(
String
route
)
{
return
fallbackProviderCache
.
get
(
route
);
ZuulFallbackProvider
provider
=
fallbackProviderCache
.
get
(
route
);
if
(
provider
==
null
)
{
provider
=
defaultFallbackProvider
;
}
return
provider
;
}
}
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringMvcContractTests.java
View file @
384c9b97
...
...
@@ -298,6 +298,19 @@ public class SpringMvcContractTests {
}
@Test
public
void
testProcessAnnotations_ListParamsWithoutName
()
throws
Exception
{
Method
method
=
TestTemplate_ListParamsWithoutName
.
class
.
getDeclaredMethod
(
"getTest"
,
List
.
class
);
MethodMetadata
data
=
this
.
contract
.
parseAndValidateMetadata
(
method
.
getDeclaringClass
(),
method
);
assertEquals
(
"/test"
,
data
.
template
().
url
());
assertEquals
(
"GET"
,
data
.
template
().
method
());
assertEquals
(
"[{id}]"
,
data
.
template
().
queries
().
get
(
"id"
).
toString
());
assertNotNull
(
data
.
indexToExpander
().
get
(
0
));
}
@Test
public
void
testProcessAnnotations_MapParams
()
throws
Exception
{
Method
method
=
TestTemplate_MapParams
.
class
.
getDeclaredMethod
(
"getTest"
,
Map
.
class
);
...
...
@@ -457,6 +470,11 @@ public class SpringMvcContractTests {
ResponseEntity
<
TestObject
>
getTest
(
@RequestParam
(
"id"
)
List
<
String
>
id
);
}
public
interface
TestTemplate_ListParamsWithoutName
{
@RequestMapping
(
value
=
"/test"
,
method
=
RequestMethod
.
GET
)
ResponseEntity
<
TestObject
>
getTest
(
@RequestParam
List
<
String
>
id
);
}
public
interface
TestTemplate_MapParams
{
@RequestMapping
(
value
=
"/test"
,
method
=
RequestMethod
.
GET
)
ResponseEntity
<
TestObject
>
getTest
(
@RequestParam
Map
<
String
,
String
>
params
);
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java
View file @
384c9b97
...
...
@@ -25,6 +25,7 @@ import static org.junit.Assert.assertThat;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
java.lang.reflect.InvocationHandler
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Proxy
;
import
java.text.ParseException
;
import
java.util.ArrayList
;
...
...
@@ -68,14 +69,19 @@ import org.springframework.web.bind.annotation.RequestParam;
import
org.springframework.web.bind.annotation.RestController
;
import
com.netflix.hystrix.HystrixCommand
;
import
com.netflix.hystrix.HystrixCommandGroupKey
;
import
com.netflix.hystrix.HystrixCommandKey
;
import
com.netflix.loadbalancer.Server
;
import
com.netflix.loadbalancer.ServerList
;
import
feign.Client
;
import
feign.Feign
;
import
feign.Logger
;
import
feign.RequestInterceptor
;
import
feign.RequestTemplate
;
import
feign.Target
;
import
feign.hystrix.FallbackFactory
;
import
feign.hystrix.SetterFactory
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
...
...
@@ -85,6 +91,7 @@ import rx.Single;
/**
* @author Spencer Gibb
* @author Jakub Narloch
* @author Erik Kringen
*/
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@SpringBootTest
(
classes
=
FeignClientTests
.
Application
.
class
,
webEnvironment
=
WebEnvironment
.
RANDOM_PORT
,
value
=
{
...
...
@@ -124,6 +131,9 @@ public class FeignClientTests {
@Qualifier
(
"localapp3FeignClient"
)
HystrixClient
namedHystrixClient
;
@Autowired
HystrixSetterFactoryClient
hystrixSetterFactoryClient
;
protected
enum
Arg
{
A
,
B
;
...
...
@@ -298,18 +308,47 @@ public class FeignClientTests {
}
}
@FeignClient
(
name
=
"localapp5"
,
configuration
=
TestHystrixSetterFactoryClientConfig
.
class
)
protected
interface
HystrixSetterFactoryClient
{
@RequestMapping
(
method
=
RequestMethod
.
GET
,
path
=
"/hellos"
)
HystrixCommand
<
List
<
Hello
>>
getHellosHystrix
();
}
public
static
class
TestHystrixSetterFactoryClientConfig
{
public
static
final
String
SETTER_PREFIX
=
"SETTER-"
;
@Bean
public
SetterFactory
commandKeyIsRequestLineSetterFactory
()
{
return
new
SetterFactory
()
{
@Override
public
HystrixCommand
.
Setter
create
(
Target
<?>
target
,
Method
method
)
{
String
groupKey
=
SETTER_PREFIX
+
target
.
name
();
RequestMapping
requestMapping
=
method
.
getAnnotation
(
RequestMapping
.
class
);
String
commandKey
=
SETTER_PREFIX
+
requestMapping
.
method
()[
0
]
+
" "
+
requestMapping
.
path
()[
0
];
return
HystrixCommand
.
Setter
.
withGroupKey
(
HystrixCommandGroupKey
.
Factory
.
asKey
(
groupKey
))
.
andCommandKey
(
HystrixCommandKey
.
Factory
.
asKey
(
commandKey
));
}
};
}
}
@Configuration
@EnableAutoConfiguration
@RestController
@EnableFeignClients
(
clients
=
{
TestClientServiceId
.
class
,
TestClient
.
class
,
DecodingTestClient
.
class
,
HystrixClient
.
class
,
HystrixClientWithFallBackFactory
.
class
},
defaultConfiguration
=
TestDefaultFeignConfig
.
class
)
DecodingTestClient
.
class
,
HystrixClient
.
class
,
HystrixClientWithFallBackFactory
.
class
,
HystrixSetterFactoryClient
.
class
},
defaultConfiguration
=
TestDefaultFeignConfig
.
class
)
@RibbonClients
({
@RibbonClient
(
name
=
"localapp"
,
configuration
=
LocalRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"localapp1"
,
configuration
=
LocalRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"localapp2"
,
configuration
=
LocalRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"localapp3"
,
configuration
=
LocalRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"localapp4"
,
configuration
=
LocalRibbonClientConfiguration
.
class
)
@RibbonClient
(
name
=
"localapp"
,
configuration
=
LocalRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"localapp1"
,
configuration
=
LocalRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"localapp2"
,
configuration
=
LocalRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"localapp3"
,
configuration
=
LocalRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"localapp4"
,
configuration
=
LocalRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"localapp5"
,
configuration
=
LocalRibbonClientConfiguration
.
class
)
})
protected
static
class
Application
{
...
...
@@ -525,12 +564,16 @@ public class FeignClientTests {
}
@Test
public
void
testHystrixCommand
()
{
public
void
testHystrixCommand
()
throws
NoSuchMethodException
{
HystrixCommand
<
List
<
Hello
>>
command
=
this
.
testClient
.
getHellosHystrix
();
assertNotNull
(
"command was null"
,
command
);
assertEquals
(
"Hystrix command group name should match the name of the feign client"
,
"localapp"
,
command
.
getCommandGroup
().
name
());
"Hystrix command group name should match the name of the feign client"
,
"localapp"
,
command
.
getCommandGroup
().
name
());
String
configKey
=
Feign
.
configKey
(
TestClient
.
class
,
TestClient
.
class
.
getMethod
(
"getHellosHystrix"
,
(
Class
<?>[])
null
));
assertEquals
(
"Hystrix command key name should match the feign config key"
,
configKey
,
command
.
getCommandKey
().
name
());
List
<
Hello
>
hellos
=
command
.
execute
();
assertNotNull
(
"hellos was null"
,
hellos
);
assertEquals
(
"hellos didn't match"
,
hellos
,
getHelloList
());
...
...
@@ -658,6 +701,25 @@ public class FeignClientTests {
assertNotNull
(
"namedHystrixClient was null"
,
this
.
namedHystrixClient
);
}
@Test
public
void
testHystrixSetterFactory
()
{
HystrixCommand
<
List
<
Hello
>>
command
=
this
.
hystrixSetterFactoryClient
.
getHellosHystrix
();
assertNotNull
(
"command was null"
,
command
);
String
setterPrefix
=
TestHystrixSetterFactoryClientConfig
.
SETTER_PREFIX
;
assertEquals
(
"Hystrix command group name should match the name of the feign client with a prefix of "
+
setterPrefix
,
setterPrefix
+
"localapp5"
,
command
.
getCommandGroup
().
name
());
assertEquals
(
"Hystrix command key name should match the request method (space) request path with a prefix of "
+
setterPrefix
,
setterPrefix
+
"GET /hellos"
,
command
.
getCommandKey
().
name
());
List
<
Hello
>
hellos
=
command
.
execute
();
assertNotNull
(
"hellos was null"
,
hellos
);
assertEquals
(
"hellos didn't match"
,
hellos
,
getHelloList
());
}
@Data
@AllArgsConstructor
@NoArgsConstructor
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonUtilsTests.java
View file @
384c9b97
...
...
@@ -110,6 +110,14 @@ public class RibbonUtilsTests {
"https://foo/%20bar?hello=1%202"
)));
}
@Test
public
void
emptyStringUri
()
throws
URISyntaxException
{
URI
original
=
new
URI
(
""
);
URI
updated
=
updateToHttpsIfNeeded
(
original
,
SECURE_CONFIG
,
SECURE_INTROSPECTOR
,
SERVER
);
Assert
.
assertThat
(
"URI should be the emptry string"
,
updated
,
is
(
new
URI
(
""
)));
}
static
DefaultClientConfigImpl
getConfig
(
boolean
value
)
{
DefaultClientConfigImpl
config
=
new
DefaultClientConfigImpl
();
config
.
setProperty
(
CommonClientConfigKey
.
IsSecure
,
value
);
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/post/SendResponseFilterTests.java
View file @
384c9b97
...
...
@@ -17,8 +17,13 @@
package
org
.
springframework
.
cloud
.
netflix
.
zuul
.
filters
.
post
;
import
java.io.ByteArrayInputStream
;
import
java.io.Closeable
;
import
java.io.IOException
;
import
java.lang.reflect.UndeclaredThrowableException
;
import
javax.servlet.ServletOutputStream
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.junit.After
;
import
org.junit.Before
;
...
...
@@ -34,9 +39,16 @@ import com.netflix.zuul.constants.ZuulConstants;
import
com.netflix.zuul.context.Debug
;
import
com.netflix.zuul.context.RequestContext
;
import
static
org
.
hamcrest
.
CoreMatchers
.
is
;
import
static
org
.
hamcrest
.
Matchers
.
equalTo
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
mockito
.
Matchers
.
anyInt
;
import
static
org
.
mockito
.
Matchers
.
isA
;
import
static
org
.
mockito
.
Mockito
.
doThrow
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
import
static
org
.
springframework
.
cloud
.
netflix
.
zuul
.
filters
.
support
.
FilterConstants
.
X_ZUUL_DEBUG_HEADER
;
/**
...
...
@@ -96,6 +108,34 @@ public class SendResponseFilterTests {
assertThat
(
"wrong origin content length"
,
contentLength
,
equalTo
(
"6"
));
}
@Test
public
void
closeResponseOutpusStreamError
()
throws
Exception
{
HttpServletResponse
response
=
mock
(
HttpServletResponse
.
class
);
RequestContext
context
=
new
RequestContext
();
context
.
setRequest
(
new
MockHttpServletRequest
());
context
.
setResponse
(
response
);
context
.
setResponseDataStream
(
new
ByteArrayInputStream
(
"Hello\n"
.
getBytes
(
"UTF-8"
)));
Closeable
zuulResponse
=
mock
(
Closeable
.
class
);
context
.
set
(
"zuulResponse"
,
zuulResponse
);
RequestContext
.
testSetCurrentContext
(
context
);
SendResponseFilter
filter
=
new
SendResponseFilter
();
ServletOutputStream
zuuloutputstream
=
mock
(
ServletOutputStream
.
class
);
doThrow
(
new
IOException
(
"Response to client closed"
)).
when
(
zuuloutputstream
).
write
(
isA
(
byte
[].
class
),
anyInt
(),
anyInt
());
when
(
response
.
getOutputStream
()).
thenReturn
(
zuuloutputstream
);
try
{
filter
.
run
();
}
catch
(
UndeclaredThrowableException
ex
)
{
assertThat
(
ex
.
getUndeclaredThrowable
().
getMessage
(),
is
(
"Response to client closed"
));
}
verify
(
zuulResponse
).
close
();
}
private
void
runFilter
(
String
characterEncoding
,
String
content
,
boolean
streamContent
)
throws
Exception
{
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
SendResponseFilter
filter
=
createFilter
(
content
,
characterEncoding
,
response
,
streamContent
);
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonCommandFallbackTests.java
View file @
384c9b97
...
...
@@ -33,7 +33,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
* @author Ryan Baxter
*/
@RunWith
(
SpringRunner
.
class
)
@SpringBootTest
(
classes
=
HttpClientRibbonCommandIntegration
Tests
.
TestConfig
.
class
,
webEnvironment
=
RANDOM_PORT
,
@SpringBootTest
(
classes
=
RibbonCommandFallback
Tests
.
TestConfig
.
class
,
webEnvironment
=
RANDOM_PORT
,
properties
=
{
"zuul.routes.simple: /simple/**"
,
"zuul.routes.another: /another/twolevel/**"
,
"ribbon.ReadTimeout: 1"
})
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/okhttp/OkHttpRibbonCommandFallbackTests.java
View file @
384c9b97
...
...
@@ -31,7 +31,7 @@ import com.netflix.zuul.context.RequestContext;
* @author Ryan Baxter
*/
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@SpringBootTest
(
classes
=
OkHttpRibbonCommandIntegration
Tests
.
TestConfig
.
class
,
webEnvironment
=
SpringBootTest
.
WebEnvironment
.
RANDOM_PORT
,
value
=
{
@SpringBootTest
(
classes
=
RibbonCommandFallback
Tests
.
TestConfig
.
class
,
webEnvironment
=
SpringBootTest
.
WebEnvironment
.
RANDOM_PORT
,
value
=
{
"zuul.routes.simple: /simple/**"
,
"zuul.routes.another: /another/twolevel/**"
,
"ribbon.ReadTimeout: 1"
})
@DirtiesContext
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/restclient/RestClientRibbonCommandFallbackTests.java
View file @
384c9b97
...
...
@@ -31,7 +31,7 @@ import com.netflix.zuul.context.RequestContext;
* @author Ryan Baxter
*/
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@SpringBootTest
(
classes
=
R
estClientRibbonCommandIntegration
Tests
.
TestConfig
.
class
,
webEnvironment
=
SpringBootTest
.
WebEnvironment
.
RANDOM_PORT
,
value
=
{
@SpringBootTest
(
classes
=
R
ibbonCommandFallback
Tests
.
TestConfig
.
class
,
webEnvironment
=
SpringBootTest
.
WebEnvironment
.
RANDOM_PORT
,
value
=
{
"zuul.routes.simple: /simple/**"
,
"zuul.routes.another: /another/twolevel/**"
,
"ribbon.ReadTimeout: 1"
})
@DirtiesContext
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/support/RibbonCommandFallbackTests.java
View file @
384c9b97
...
...
@@ -18,13 +18,35 @@
package
org
.
springframework
.
cloud
.
netflix
.
zuul
.
filters
.
route
.
support
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.Collections
;
import
java.util.Set
;
import
org.junit.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.autoconfigure.web.ErrorAttributes
;
import
org.springframework.boot.context.embedded.LocalServerPort
;
import
org.springframework.boot.test.web.client.TestRestTemplate
;
import
org.springframework.cloud.netflix.ribbon.RibbonClient
;
import
org.springframework.cloud.netflix.ribbon.RibbonClients
;
import
org.springframework.cloud.netflix.ribbon.SpringClientFactory
;
import
org.springframework.cloud.netflix.zuul.EnableZuulProxy
;
import
org.springframework.cloud.netflix.zuul.filters.ZuulProperties
;
import
org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory
;
import
org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider
;
import
org.springframework.cloud.netflix.zuul.filters.route.apache.HttpClientRibbonCommandFactory
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.client.ClientHttpResponse
;
import
org.springframework.web.bind.annotation.RestController
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
...
...
@@ -47,11 +69,90 @@ public abstract class RibbonCommandFallbackTests {
}
@Test
public
void
no
Fallback
()
{
public
void
default
Fallback
()
{
String
uri
=
"/another/twolevel/slow"
;
ResponseEntity
<
String
>
result
=
new
TestRestTemplate
().
exchange
(
"http://localhost:"
+
this
.
port
+
uri
,
HttpMethod
.
GET
,
new
HttpEntity
<>((
Void
)
null
),
String
.
class
);
assertEquals
(
HttpStatus
.
INTERNAL_SERVER_ERROR
,
result
.
getStatusCode
());
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
"default fallback"
,
result
.
getBody
());
}
// Don't use @SpringBootApplication because we don't want to component scan
@Configuration
@EnableAutoConfiguration
@RestController
@EnableZuulProxy
@RibbonClients
({
@RibbonClient
(
name
=
"simple"
,
configuration
=
ZuulProxyTestBase
.
SimpleRibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"another"
,
configuration
=
ZuulProxyTestBase
.
AnotherRibbonClientConfiguration
.
class
)})
public
static
class
TestConfig
extends
ZuulProxyTestBase
.
AbstractZuulProxyApplication
{
@Autowired
(
required
=
false
)
private
Set
<
ZuulFallbackProvider
>
zuulFallbackProviders
=
Collections
.
emptySet
();
@Bean
public
RibbonCommandFactory
<?>
ribbonCommandFactory
(
final
SpringClientFactory
clientFactory
)
{
return
new
HttpClientRibbonCommandFactory
(
clientFactory
,
new
ZuulProperties
(),
zuulFallbackProviders
);
}
@Bean
public
ZuulProxyTestBase
.
MyErrorController
myErrorController
(
ErrorAttributes
errorAttributes
)
{
return
new
ZuulProxyTestBase
.
MyErrorController
(
errorAttributes
);
}
@Bean
public
ZuulFallbackProvider
defaultFallbackProvider
()
{
return
new
DefaultFallbackProvider
();
}
}
public
static
class
DefaultFallbackProvider
implements
ZuulFallbackProvider
{
@Override
public
String
getRoute
()
{
return
"*"
;
}
@Override
public
ClientHttpResponse
fallbackResponse
()
{
return
new
ClientHttpResponse
()
{
@Override
public
HttpStatus
getStatusCode
()
throws
IOException
{
return
HttpStatus
.
OK
;
}
@Override
public
int
getRawStatusCode
()
throws
IOException
{
return
200
;
}
@Override
public
String
getStatusText
()
throws
IOException
{
return
null
;
}
@Override
public
void
close
()
{
}
@Override
public
InputStream
getBody
()
throws
IOException
{
return
new
ByteArrayInputStream
(
"default fallback"
.
getBytes
());
}
@Override
public
HttpHeaders
getHeaders
()
{
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
TEXT_HTML
);
return
headers
;
}
};
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment