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
7f7cdccb
Commit
7f7cdccb
authored
Jun 09, 2017
by
Ryan Baxter
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master' into 2.0.x
parents
c046901d
f9424231
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
117 additions
and
78 deletions
+117
-78
ArchaiusAutoConfiguration.java
...ork/cloud/netflix/archaius/ArchaiusAutoConfiguration.java
+21
-10
RibbonLoadBalancedRetryPolicy.java
...k/cloud/netflix/ribbon/RibbonLoadBalancedRetryPolicy.java
+7
-7
AdhocTestSuite.java
...ava/org/springframework/cloud/netflix/AdhocTestSuite.java
+5
-7
FeignAcceptEncodingTests.java
...loud/netflix/feign/encoding/FeignAcceptEncodingTests.java
+11
-8
RibbonDisabledTests.java
...ngframework/cloud/netflix/ribbon/RibbonDisabledTests.java
+5
-3
RibbonLoadBalancedRetryPolicyFactoryTest.java
...flix/ribbon/RibbonLoadBalancedRetryPolicyFactoryTest.java
+3
-2
RetryableZuulProxyApplicationTests.java
...loud/netflix/zuul/RetryableZuulProxyApplicationTests.java
+4
-3
ZuulProxyAutoConfigurationTests.java
...k/cloud/netflix/zuul/ZuulProxyAutoConfigurationTests.java
+3
-1
RibbonRetryIntegrationTestBase.java
...filters/route/support/RibbonRetryIntegrationTestBase.java
+31
-22
ZuulProxyTestBase.java
...netflix/zuul/filters/route/support/ZuulProxyTestBase.java
+27
-15
No files found.
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/archaius/ArchaiusAutoConfiguration.java
View file @
7f7cdccb
...
@@ -24,12 +24,21 @@ import java.util.concurrent.atomic.AtomicBoolean;
...
@@ -24,12 +24,21 @@ import java.util.concurrent.atomic.AtomicBoolean;
import
javax.annotation.PreDestroy
;
import
javax.annotation.PreDestroy
;
import
com.netflix.config.AggregatedConfiguration
;
import
com.netflix.config.ConcurrentCompositeConfiguration
;
import
com.netflix.config.ConfigurationManager
;
import
com.netflix.config.DeploymentContext
;
import
com.netflix.config.DynamicProperty
;
import
com.netflix.config.DynamicPropertyFactory
;
import
com.netflix.config.DynamicURLConfiguration
;
import
org.apache.commons.configuration.AbstractConfiguration
;
import
org.apache.commons.configuration.AbstractConfiguration
;
import
org.apache.commons.configuration.ConfigurationBuilder
;
import
org.apache.commons.configuration.ConfigurationBuilder
;
import
org.apache.commons.configuration.EnvironmentConfiguration
;
import
org.apache.commons.configuration.EnvironmentConfiguration
;
import
org.apache.commons.configuration.SystemConfiguration
;
import
org.apache.commons.configuration.SystemConfiguration
;
import
org.apache.commons.configuration.event.ConfigurationEvent
;
import
org.apache.commons.configuration.event.ConfigurationEvent
;
import
org.apache.commons.configuration.event.ConfigurationListener
;
import
org.apache.commons.configuration.event.ConfigurationListener
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint
;
import
org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint
;
import
org.springframework.boot.actuate.endpoint.Endpoint
;
import
org.springframework.boot.actuate.endpoint.Endpoint
;
...
@@ -46,14 +55,6 @@ import org.springframework.core.env.ConfigurableEnvironment;
...
@@ -46,14 +55,6 @@ import org.springframework.core.env.ConfigurableEnvironment;
import
org.springframework.core.env.Environment
;
import
org.springframework.core.env.Environment
;
import
org.springframework.util.ReflectionUtils
;
import
org.springframework.util.ReflectionUtils
;
import
com.netflix.config.AggregatedConfiguration
;
import
com.netflix.config.ConcurrentCompositeConfiguration
;
import
com.netflix.config.ConfigurationManager
;
import
com.netflix.config.DeploymentContext
;
import
com.netflix.config.DynamicProperty
;
import
com.netflix.config.DynamicPropertyFactory
;
import
com.netflix.config.DynamicURLConfiguration
;
import
static
com
.
netflix
.
config
.
ConfigurationManager
.
APPLICATION_PROPERTIES
;
import
static
com
.
netflix
.
config
.
ConfigurationManager
.
APPLICATION_PROPERTIES
;
import
static
com
.
netflix
.
config
.
ConfigurationManager
.
DISABLE_DEFAULT_ENV_CONFIG
;
import
static
com
.
netflix
.
config
.
ConfigurationManager
.
DISABLE_DEFAULT_ENV_CONFIG
;
import
static
com
.
netflix
.
config
.
ConfigurationManager
.
DISABLE_DEFAULT_SYS_CONFIG
;
import
static
com
.
netflix
.
config
.
ConfigurationManager
.
DISABLE_DEFAULT_SYS_CONFIG
;
...
@@ -75,8 +76,19 @@ public class ArchaiusAutoConfiguration {
...
@@ -75,8 +76,19 @@ public class ArchaiusAutoConfiguration {
private
static
final
AtomicBoolean
initialized
=
new
AtomicBoolean
(
false
);
private
static
final
AtomicBoolean
initialized
=
new
AtomicBoolean
(
false
);
@Autowired
private
ConfigurableEnvironment
env
;
@Autowired
(
required
=
false
)
private
List
<
AbstractConfiguration
>
externalConfigurations
=
new
ArrayList
<>();
private
static
DynamicURLConfiguration
defaultURLConfig
;
@PreDestroy
@PreDestroy
public
void
close
()
{
public
void
close
()
{
if
(
defaultURLConfig
!=
null
)
{
defaultURLConfig
.
stopLoading
();
}
setStatic
(
ConfigurationManager
.
class
,
"instance"
,
null
);
setStatic
(
ConfigurationManager
.
class
,
"instance"
,
null
);
setStatic
(
ConfigurationManager
.
class
,
"customConfigurationInstalled"
,
false
);
setStatic
(
ConfigurationManager
.
class
,
"customConfigurationInstalled"
,
false
);
setStatic
(
DynamicPropertyFactory
.
class
,
"config"
,
null
);
setStatic
(
DynamicPropertyFactory
.
class
,
"config"
,
null
);
...
@@ -152,8 +164,7 @@ public class ArchaiusAutoConfiguration {
...
@@ -152,8 +164,7 @@ public class ArchaiusAutoConfiguration {
config
.
addConfiguration
(
envConfig
,
config
.
addConfiguration
(
envConfig
,
ConfigurableEnvironmentConfiguration
.
class
.
getSimpleName
());
ConfigurableEnvironmentConfiguration
.
class
.
getSimpleName
());
// below come from ConfigurationManager.createDefaultConfigInstance()
defaultURLConfig
=
new
DynamicURLConfiguration
();
DynamicURLConfiguration
defaultURLConfig
=
new
DynamicURLConfiguration
();
try
{
try
{
config
.
addConfiguration
(
defaultURLConfig
,
URL_CONFIG_NAME
);
config
.
addConfiguration
(
defaultURLConfig
,
URL_CONFIG_NAME
);
}
}
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancedRetryPolicy.java
View file @
7f7cdccb
...
@@ -18,17 +18,17 @@
...
@@ -18,17 +18,17 @@
package
org
.
springframework
.
cloud
.
netflix
.
ribbon
;
package
org
.
springframework
.
cloud
.
netflix
.
ribbon
;
import
java.util.ArrayList
;
import
com.netflix.client.config.CommonClientConfigKey
;
import
java.util.List
;
import
com.netflix.client.config.IClientConfig
;
import
com.netflix.client.config.IClientConfigKey
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy
;
import
org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser
;
import
org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser
;
import
org.springframework.core.env.Environment
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.util.StringUtils
;
import
org.springframework.util.StringUtils
;
import
com.netflix.client.config.CommonClientConfigKey
;
import
com.netflix.client.config.IClientConfig
;
import
java.util.ArrayList
;
import
com.netflix.client.config.IClientConfigKey
;
import
java.util.List
;
/**
/**
* {@link LoadBalancedRetryPolicy} for Ribbon clients.
* {@link LoadBalancedRetryPolicy} for Ribbon clients.
...
@@ -60,7 +60,7 @@ public class RibbonLoadBalancedRetryPolicy implements LoadBalancedRetryPolicy {
...
@@ -60,7 +60,7 @@ public class RibbonLoadBalancedRetryPolicy implements LoadBalancedRetryPolicy {
for
(
String
code
:
retryableStatusCodesArray
)
{
for
(
String
code
:
retryableStatusCodesArray
)
{
if
(!
StringUtils
.
isEmpty
(
code
))
{
if
(!
StringUtils
.
isEmpty
(
code
))
{
try
{
try
{
retryableStatusCodes
.
add
(
Integer
.
valueOf
(
code
));
retryableStatusCodes
.
add
(
Integer
.
valueOf
(
code
.
trim
()
));
}
catch
(
NumberFormatException
e
)
{
}
catch
(
NumberFormatException
e
)
{
//TODO log
//TODO log
}
}
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/AdhocTestSuite.java
View file @
7f7cdccb
...
@@ -20,11 +20,9 @@ import org.junit.Ignore;
...
@@ -20,11 +20,9 @@ import org.junit.Ignore;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.junit.runners.Suite
;
import
org.junit.runners.Suite
;
import
org.junit.runners.Suite.SuiteClasses
;
import
org.junit.runners.Suite.SuiteClasses
;
import
org.springframework.cloud.netflix.feign.encoding.FeignAcceptEncodingTests
;
import
org.springframework.cloud.netflix.metrics.servo.ServoMetricReaderTests
;
import
org.springframework.cloud.netflix.zuul.FormZuulServletProxyApplicationTests
;
import
org.springframework.cloud.netflix.ribbon.RibbonInterceptorTests
;
import
org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfigurationTests
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClientTests
;
import
org.springframework.cloud.netflix.zuul.ZuulProxyConfigurationTests
;
/**
/**
* A test suite for probing weird ordering problems in the tests.
* A test suite for probing weird ordering problems in the tests.
...
@@ -32,8 +30,8 @@ import org.springframework.cloud.netflix.zuul.ZuulProxyConfigurationTests;
...
@@ -32,8 +30,8 @@ import org.springframework.cloud.netflix.zuul.ZuulProxyConfigurationTests;
* @author Dave Syer
* @author Dave Syer
*/
*/
@RunWith
(
Suite
.
class
)
@RunWith
(
Suite
.
class
)
@SuiteClasses
({
RibbonLoadBalancerClientTests
.
class
,
RibbonInterceptorTests
.
class
,
FeignAcceptEncoding
Tests
.
class
,
@SuiteClasses
({
ZuulProxyAutoConfiguration
Tests
.
class
,
ServoMetricReaderTests
.
class
,
ZuulProxyConfigur
ationTests
.
class
})
FormZuulServletProxyApplic
ationTests
.
class
})
@Ignore
@Ignore
public
class
AdhocTestSuite
{
public
class
AdhocTestSuite
{
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/encoding/FeignAcceptEncodingTests.java
View file @
7f7cdccb
...
@@ -16,14 +16,16 @@
...
@@ -16,14 +16,16 @@
package
org
.
springframework
.
cloud
.
netflix
.
feign
.
encoding
;
package
org
.
springframework
.
cloud
.
netflix
.
feign
.
encoding
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
import
com.netflix.loadbalancer.BaseLoadBalancer
;
import
com.netflix.loadbalancer.ILoadBalancer
;
import
com.netflix.loadbalancer.Server
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
...
@@ -37,11 +39,11 @@ import org.springframework.context.annotation.Bean;
...
@@ -37,11 +39,11 @@ import org.springframework.context.annotation.Bean;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
import
org.springframework.test.annotation.DirtiesContext
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
com.netflix.loadbalancer.BaseLoadBalancer
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
com.netflix.loadbalancer.ILoadBalancer
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
com.netflix.loadbalancer.Server
;
/**
/**
* Tests the response compression.
* Tests the response compression.
...
@@ -50,7 +52,8 @@ import com.netflix.loadbalancer.Server;
...
@@ -50,7 +52,8 @@ import com.netflix.loadbalancer.Server;
*/
*/
@SpringBootTest
(
classes
=
FeignAcceptEncodingTests
.
Application
.
class
,
webEnvironment
=
WebEnvironment
.
RANDOM_PORT
,
value
=
{
@SpringBootTest
(
classes
=
FeignAcceptEncodingTests
.
Application
.
class
,
webEnvironment
=
WebEnvironment
.
RANDOM_PORT
,
value
=
{
"feign.compression.response.enabled=true"
})
"feign.compression.response.enabled=true"
})
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@RunWith
(
SpringRunner
.
class
)
@DirtiesContext
public
class
FeignAcceptEncodingTests
{
public
class
FeignAcceptEncodingTests
{
@Autowired
@Autowired
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonDisabledTests.java
View file @
7f7cdccb
...
@@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.ribbon;
...
@@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.ribbon;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.cloud.test.ClassPathExclusions
;
import
org.springframework.cloud.test.ClassPathExclusions
;
import
org.springframework.cloud.test.ModifiedClassPathRunner
;
import
org.springframework.cloud.test.ModifiedClassPathRunner
;
...
@@ -27,12 +28,12 @@ import org.springframework.cloud.test.ModifiedClassPathRunner;
...
@@ -27,12 +28,12 @@ import org.springframework.cloud.test.ModifiedClassPathRunner;
* @author Ryan Baxter
* @author Ryan Baxter
*/
*/
@RunWith
(
ModifiedClassPathRunner
.
class
)
@RunWith
(
ModifiedClassPathRunner
.
class
)
@ClassPathExclusions
(
{
"ribbon-{version:\\d.*}.jar"
}
)
@ClassPathExclusions
(
{
"ribbon-{version:\\d.*}.jar"
}
)
public
class
RibbonDisabledTests
{
public
class
RibbonDisabledTests
{
@Test
(
expected
=
ArrayStoreException
.
class
)
@Test
(
expected
=
ArrayStoreException
.
class
)
public
void
testRibbonDisabled
()
{
public
void
testRibbonDisabled
()
{
new
SpringApplicationBuilder
().
web
(
false
)
new
SpringApplicationBuilder
().
web
(
false
)
.
sources
(
RibbonAutoConfiguration
.
class
)
.
sources
(
RibbonAutoConfiguration
.
class
).
run
();
.
run
().
close
();
}
}
}
}
\ No newline at end of file
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancedRetryPolicyFactoryTest.java
View file @
7f7cdccb
...
@@ -201,7 +201,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
...
@@ -201,7 +201,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
}
}
@Test
@Test
public
void
testRetryableStatusCodes
t
()
throws
Exception
{
public
void
testRetryableStatusCodes
()
throws
Exception
{
int
sameServer
=
3
;
int
sameServer
=
3
;
int
nextServer
=
3
;
int
nextServer
=
3
;
RibbonServer
server
=
getRibbonServer
();
RibbonServer
server
=
getRibbonServer
();
...
@@ -210,7 +210,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
...
@@ -210,7 +210,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
doReturn
(
nextServer
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
nextServer
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
false
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
eq
(
false
));
doReturn
(
false
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
eq
(
false
));
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
server
.
getServiceId
()));
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
server
.
getServiceId
()));
doReturn
(
"404,502,foo, ,"
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
doReturn
(
"404,
418,
502,foo, ,"
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
clientFactory
.
getLoadBalancerContext
(
server
.
getServiceId
()).
setRetryHandler
(
new
DefaultLoadBalancerRetryHandler
(
config
));
clientFactory
.
getLoadBalancerContext
(
server
.
getServiceId
()).
setRetryHandler
(
new
DefaultLoadBalancerRetryHandler
(
config
));
RibbonLoadBalancerClient
client
=
getRibbonLoadBalancerClient
(
server
);
RibbonLoadBalancerClient
client
=
getRibbonLoadBalancerClient
(
server
);
RibbonLoadBalancedRetryPolicyFactory
factory
=
new
RibbonLoadBalancedRetryPolicyFactory
(
clientFactory
);
RibbonLoadBalancedRetryPolicyFactory
factory
=
new
RibbonLoadBalancedRetryPolicyFactory
(
clientFactory
);
...
@@ -219,6 +219,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
...
@@ -219,6 +219,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
doReturn
(
HttpMethod
.
GET
).
when
(
request
).
getMethod
();
doReturn
(
HttpMethod
.
GET
).
when
(
request
).
getMethod
();
assertThat
(
policy
.
retryableStatusCode
(
400
),
is
(
false
));
assertThat
(
policy
.
retryableStatusCode
(
400
),
is
(
false
));
assertThat
(
policy
.
retryableStatusCode
(
404
),
is
(
true
));
assertThat
(
policy
.
retryableStatusCode
(
404
),
is
(
true
));
assertThat
(
policy
.
retryableStatusCode
(
418
),
is
(
true
));
assertThat
(
policy
.
retryableStatusCode
(
502
),
is
(
true
));
assertThat
(
policy
.
retryableStatusCode
(
502
),
is
(
true
));
}
}
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/RetryableZuulProxyApplicationTests.java
View file @
7f7cdccb
...
@@ -60,7 +60,8 @@ import com.netflix.zuul.context.RequestContext;
...
@@ -60,7 +60,8 @@ import com.netflix.zuul.context.RequestContext;
value
=
{
value
=
{
"zuul.routes.simple.path: /simple/**"
,
"zuul.routes.simple.path: /simple/**"
,
"zuul.routes.simple.retryable: true"
,
"zuul.routes.simple.retryable: true"
,
"ribbon.OkToRetryOnAllOperations: true"
})
"ribbon.OkToRetryOnAllOperations: true"
,
"simple.ribbon.retryableStatusCodes: 404"
})
@DirtiesContext
@DirtiesContext
public
class
RetryableZuulProxyApplicationTests
{
public
class
RetryableZuulProxyApplicationTests
{
...
@@ -88,7 +89,7 @@ public class RetryableZuulProxyApplicationTests {
...
@@ -88,7 +89,7 @@ public class RetryableZuulProxyApplicationTests {
HttpHeaders
headers
=
new
HttpHeaders
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_FORM_URLENCODED
);
headers
.
setContentType
(
MediaType
.
APPLICATION_FORM_URLENCODED
);
ResponseEntity
<
String
>
result
=
testRestTemplate
.
exchange
(
ResponseEntity
<
String
>
result
=
testRestTemplate
.
exchange
(
"/simple"
,
HttpMethod
.
POST
,
"/simple
/poster
"
,
HttpMethod
.
POST
,
new
HttpEntity
<>(
form
,
headers
),
String
.
class
);
new
HttpEntity
<>(
form
,
headers
),
String
.
class
);
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
"Posted! {foo=[bar]}"
,
result
.
getBody
());
assertEquals
(
"Posted! {foo=[bar]}"
,
result
.
getBody
());
...
@@ -104,7 +105,7 @@ public class RetryableZuulProxyApplicationTests {
...
@@ -104,7 +105,7 @@ public class RetryableZuulProxyApplicationTests {
@RibbonClient
(
name
=
"simple"
,
configuration
=
RetryableRibbonClientConfiguration
.
class
)
@RibbonClient
(
name
=
"simple"
,
configuration
=
RetryableRibbonClientConfiguration
.
class
)
class
RetryableZuulProxyApplication
{
class
RetryableZuulProxyApplication
{
@RequestMapping
(
value
=
"/"
,
method
=
RequestMethod
.
POST
)
@RequestMapping
(
value
=
"/
poster
"
,
method
=
RequestMethod
.
POST
)
public
String
delete
(
@RequestBody
MultiValueMap
<
String
,
String
>
form
)
{
public
String
delete
(
@RequestBody
MultiValueMap
<
String
,
String
>
form
)
{
return
"Posted! "
+
form
;
return
"Posted! "
+
form
;
}
}
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulProxyAutoConfigurationTests.java
View file @
7f7cdccb
...
@@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.zuul;
...
@@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.zuul;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.boot.test.context.SpringBootTest
;
...
@@ -26,6 +27,7 @@ import org.springframework.cloud.netflix.zuul.filters.CompositeRouteLocator;
...
@@ -26,6 +27,7 @@ import org.springframework.cloud.netflix.zuul.filters.CompositeRouteLocator;
import
org.springframework.cloud.netflix.zuul.filters.RouteLocator
;
import
org.springframework.cloud.netflix.zuul.filters.RouteLocator
;
import
org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter
;
import
org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.test.annotation.DirtiesContext
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
...
@@ -39,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
...
@@ -39,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@RunWith
(
SpringRunner
.
class
)
@RunWith
(
SpringRunner
.
class
)
@SpringBootTest
@SpringBootTest
@DirtiesContext
public
class
ZuulProxyAutoConfigurationTests
{
public
class
ZuulProxyAutoConfigurationTests
{
@Autowired
@Autowired
...
@@ -53,7 +56,6 @@ public class ZuulProxyAutoConfigurationTests {
...
@@ -53,7 +56,6 @@ public class ZuulProxyAutoConfigurationTests {
assertThat
(
this
.
ribbonRoutingFilter
).
isNotNull
();
assertThat
(
this
.
ribbonRoutingFilter
).
isNotNull
();
}
}
@Configuration
@Configuration
@EnableAutoConfiguration
@EnableAutoConfiguration
@EnableZuulProxy
@EnableZuulProxy
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/support/RibbonRetryIntegrationTestBase.java
View file @
7f7cdccb
...
@@ -18,10 +18,15 @@
...
@@ -18,10 +18,15 @@
package
org
.
springframework
.
cloud
.
netflix
.
zuul
.
filters
.
route
.
support
;
package
org
.
springframework
.
cloud
.
netflix
.
zuul
.
filters
.
route
.
support
;
import
com.netflix.loadbalancer.Server
;
import
com.netflix.loadbalancer.ServerList
;
import
com.netflix.zuul.context.RequestContext
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.apache.commons.logging.LogFactory
;
import
org.junit.Before
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.test.web.client.TestRestTemplate
;
import
org.springframework.boot.test.web.client.TestRestTemplate
;
...
@@ -47,10 +52,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
...
@@ -47,10 +52,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
import
org.springframework.web.bind.annotation.ResponseStatus
;
import
org.springframework.web.bind.annotation.ResponseStatus
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
import
com.netflix.loadbalancer.Server
;
import
com.netflix.loadbalancer.ServerList
;
import
com.netflix.zuul.context.RequestContext
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
/**
...
@@ -67,12 +68,10 @@ public abstract class RibbonRetryIntegrationTestBase {
...
@@ -67,12 +68,10 @@ public abstract class RibbonRetryIntegrationTestBase {
public
void
setup
()
{
public
void
setup
()
{
RequestContext
.
getCurrentContext
().
clear
();
RequestContext
.
getCurrentContext
().
clear
();
String
uri
=
"/resetError"
;
String
uri
=
"/resetError"
;
new
TestRestTemplate
().
exchange
(
new
TestRestTemplate
().
exchange
(
"http://localhost:"
+
this
.
port
+
uri
,
"http://localhost:"
+
this
.
port
+
uri
,
HttpMethod
.
GET
,
HttpMethod
.
GET
,
new
HttpEntity
<>((
Void
)
null
),
String
.
class
);
new
HttpEntity
<>((
Void
)
null
),
String
.
class
);
}
}
@Test
@Test
public
void
retryable
()
{
public
void
retryable
()
{
String
uri
=
"/retryable/everyothererror"
;
String
uri
=
"/retryable/everyothererror"
;
...
@@ -147,9 +146,11 @@ public abstract class RibbonRetryIntegrationTestBase {
...
@@ -147,9 +146,11 @@ public abstract class RibbonRetryIntegrationTestBase {
@RibbonClient
(
name
=
"retryable"
,
configuration
=
RibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"retryable"
,
configuration
=
RibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"disableretry"
,
configuration
=
RibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"disableretry"
,
configuration
=
RibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"globalretrydisabled"
,
configuration
=
RibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"globalretrydisabled"
,
configuration
=
RibbonClientConfiguration
.
class
),
@RibbonClient
(
name
=
"getretryable"
,
configuration
=
RibbonClientConfiguration
.
class
)})
@RibbonClient
(
name
=
"getretryable"
,
configuration
=
RibbonClientConfiguration
.
class
)
})
public
static
class
RetryableTestConfig
{
public
static
class
RetryableTestConfig
{
private
final
Log
LOG
=
LogFactory
.
getLog
(
RetryableTestConfig
.
class
);
private
boolean
error
=
true
;
private
boolean
error
=
true
;
@RequestMapping
(
"/resetError"
)
@RequestMapping
(
"/resetError"
)
...
@@ -162,13 +163,14 @@ public abstract class RibbonRetryIntegrationTestBase {
...
@@ -162,13 +163,14 @@ public abstract class RibbonRetryIntegrationTestBase {
boolean
shouldError
=
error
;
boolean
shouldError
=
error
;
error
=
!
error
;
error
=
!
error
;
try
{
try
{
if
(
shouldError
)
{
if
(
shouldError
)
{
Thread
.
sleep
(
80000
);
Thread
.
sleep
(
80000
);
}
}
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
}
}
catch
(
InterruptedException
e
)
{
LOG
.
info
(
e
);
Thread
.
currentThread
().
interrupt
();
}
return
new
ResponseEntity
<
String
>(
"no error"
,
HttpStatus
.
OK
);
return
new
ResponseEntity
<
String
>(
"no error"
,
HttpStatus
.
OK
);
}
}
...
@@ -183,7 +185,7 @@ public abstract class RibbonRetryIntegrationTestBase {
...
@@ -183,7 +185,7 @@ public abstract class RibbonRetryIntegrationTestBase {
public
ResponseEntity
<
String
>
fourOFourError
()
{
public
ResponseEntity
<
String
>
fourOFourError
()
{
boolean
shouldError
=
error
;
boolean
shouldError
=
error
;
error
=
!
error
;
error
=
!
error
;
if
(
shouldError
)
{
if
(
shouldError
)
{
return
new
ResponseEntity
<
String
>(
"not found"
,
HttpStatus
.
NOT_FOUND
);
return
new
ResponseEntity
<
String
>(
"not found"
,
HttpStatus
.
NOT_FOUND
);
}
}
return
new
ResponseEntity
<
String
>(
"no error"
,
HttpStatus
.
OK
);
return
new
ResponseEntity
<
String
>(
"no error"
,
HttpStatus
.
OK
);
...
@@ -204,14 +206,17 @@ public abstract class RibbonRetryIntegrationTestBase {
...
@@ -204,14 +206,17 @@ public abstract class RibbonRetryIntegrationTestBase {
}
}
@Configuration
@Configuration
public
static
class
FourOFourRetryableRibbonConfiguration
extends
RibbonClientConfiguration
{
public
static
class
FourOFourRetryableRibbonConfiguration
extends
RibbonClientConfiguration
{
@Bean
@Bean
public
LoadBalancedRetryPolicyFactory
loadBalancedRetryPolicyFactory
(
SpringClientFactory
factory
)
{
public
LoadBalancedRetryPolicyFactory
loadBalancedRetryPolicyFactory
(
SpringClientFactory
factory
)
{
return
new
MyRibbonRetryPolicyFactory
(
factory
);
return
new
MyRibbonRetryPolicyFactory
(
factory
);
}
}
public
static
class
MyRibbonRetryPolicyFactory
extends
RibbonLoadBalancedRetryPolicyFactory
{
public
static
class
MyRibbonRetryPolicyFactory
extends
RibbonLoadBalancedRetryPolicyFactory
{
private
SpringClientFactory
factory
;
private
SpringClientFactory
factory
;
...
@@ -221,21 +226,25 @@ public abstract class RibbonRetryIntegrationTestBase {
...
@@ -221,21 +226,25 @@ public abstract class RibbonRetryIntegrationTestBase {
}
}
@Override
@Override
public
LoadBalancedRetryPolicy
create
(
String
serviceId
,
ServiceInstanceChooser
loadBalanceChooser
)
{
public
LoadBalancedRetryPolicy
create
(
String
serviceId
,
ServiceInstanceChooser
loadBalanceChooser
)
{
RibbonLoadBalancerContext
lbContext
=
this
.
factory
RibbonLoadBalancerContext
lbContext
=
this
.
factory
.
getLoadBalancerContext
(
serviceId
);
.
getLoadBalancerContext
(
serviceId
);
return
new
MyLoadBalancedRetryPolicy
(
serviceId
,
lbContext
,
loadBalanceChooser
);
return
new
MyLoadBalancedRetryPolicy
(
serviceId
,
lbContext
,
loadBalanceChooser
);
}
}
class
MyLoadBalancedRetryPolicy
extends
RibbonLoadBalancedRetryPolicy
{
class
MyLoadBalancedRetryPolicy
extends
RibbonLoadBalancedRetryPolicy
{
public
MyLoadBalancedRetryPolicy
(
String
serviceId
,
RibbonLoadBalancerContext
context
,
ServiceInstanceChooser
loadBalanceChooser
)
{
public
MyLoadBalancedRetryPolicy
(
String
serviceId
,
RibbonLoadBalancerContext
context
,
ServiceInstanceChooser
loadBalanceChooser
)
{
super
(
serviceId
,
context
,
loadBalanceChooser
);
super
(
serviceId
,
context
,
loadBalanceChooser
);
}
}
@Override
@Override
public
boolean
retryableStatusCode
(
int
statusCode
)
{
public
boolean
retryableStatusCode
(
int
statusCode
)
{
if
(
statusCode
==
HttpStatus
.
NOT_FOUND
.
value
())
{
if
(
statusCode
==
HttpStatus
.
NOT_FOUND
.
value
())
{
return
true
;
return
true
;
}
}
return
super
.
retryableStatusCode
(
statusCode
);
return
super
.
retryableStatusCode
(
statusCode
);
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/support/ZuulProxyTestBase.java
View file @
7f7cdccb
...
@@ -30,8 +30,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
...
@@ -30,8 +30,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequest
;
import
com.netflix.loadbalancer.Server
;
import
com.netflix.loadbalancer.ServerList
;
import
com.netflix.zuul.ZuulFilter
;
import
com.netflix.zuul.context.RequestContext
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.junit.Before
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.web.ErrorProperties
;
import
org.springframework.boot.autoconfigure.web.ErrorProperties
;
...
@@ -45,6 +53,7 @@ import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
...
@@ -45,6 +53,7 @@ import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import
org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator
;
import
org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator
;
import
org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory
;
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.ZuulFallbackProvider
;
import
org.springframework.cloud.netflix.zuul.filters.route.support.RibbonRetryIntegrationTestBase.RetryableTestConfig
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpEntity
;
...
@@ -68,11 +77,6 @@ import org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfigu
...
@@ -68,11 +77,6 @@ import org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfigu
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
;
import
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
;
import
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
;
import
com.netflix.loadbalancer.Server
;
import
com.netflix.loadbalancer.ServerList
;
import
com.netflix.zuul.ZuulFilter
;
import
com.netflix.zuul.context.RequestContext
;
import
static
org
.
hamcrest
.
Matchers
.
is
;
import
static
org
.
hamcrest
.
Matchers
.
is
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
...
@@ -217,12 +221,13 @@ public abstract class ZuulProxyTestBase {
...
@@ -217,12 +221,13 @@ public abstract class ZuulProxyTestBase {
public
void
ribbonDeleteWithBody
()
{
public
void
ribbonDeleteWithBody
()
{
this
.
endpoint
.
reset
();
this
.
endpoint
.
reset
();
ResponseEntity
<
String
>
result
=
new
TestRestTemplate
().
exchange
(
ResponseEntity
<
String
>
result
=
new
TestRestTemplate
().
exchange
(
"http://localhost:"
+
this
.
port
+
"/simple/deletewithbody"
,
HttpMethod
.
DELETE
,
"http://localhost:"
+
this
.
port
+
"/simple/deletewithbody"
,
new
HttpEntity
<>(
"deleterequestbody"
),
String
.
class
);
HttpMethod
.
DELETE
,
new
HttpEntity
<>(
"deleterequestbody"
),
String
.
class
);
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
if
(
supportsDeleteWithBody
())
{
if
(
supportsDeleteWithBody
())
{
assertEquals
(
"Deleted deleterequestbody"
,
result
.
getBody
());
assertEquals
(
"Deleted deleterequestbody"
,
result
.
getBody
());
}
else
{
}
else
{
assertEquals
(
"Deleted null"
,
result
.
getBody
());
assertEquals
(
"Deleted null"
,
result
.
getBody
());
}
}
}
}
...
@@ -310,6 +315,8 @@ public abstract class ZuulProxyTestBase {
...
@@ -310,6 +315,8 @@ public abstract class ZuulProxyTestBase {
public
static
abstract
class
AbstractZuulProxyApplication
public
static
abstract
class
AbstractZuulProxyApplication
extends
DelegatingWebMvcConfiguration
{
extends
DelegatingWebMvcConfiguration
{
private
final
Log
LOG
=
LogFactory
.
getLog
(
RetryableTestConfig
.
class
);
@RequestMapping
(
value
=
"/local/{id}"
,
method
=
RequestMethod
.
PATCH
)
@RequestMapping
(
value
=
"/local/{id}"
,
method
=
RequestMethod
.
PATCH
)
public
String
patch
(
@PathVariable
final
String
id
,
public
String
patch
(
@PathVariable
final
String
id
,
@RequestBody
final
String
body
)
{
@RequestBody
final
String
body
)
{
...
@@ -329,7 +336,8 @@ public abstract class ZuulProxyTestBase {
...
@@ -329,7 +336,8 @@ public abstract class ZuulProxyTestBase {
@RequestMapping
(
value
=
"/local"
,
method
=
RequestMethod
.
POST
)
@RequestMapping
(
value
=
"/local"
,
method
=
RequestMethod
.
POST
)
public
String
postWithFormParam
(
HttpServletRequest
request
,
public
String
postWithFormParam
(
HttpServletRequest
request
,
@RequestBody
MultiValueMap
<
String
,
String
>
body
)
{
@RequestBody
MultiValueMap
<
String
,
String
>
body
)
{
return
"Posted "
+
body
.
get
(
"foo"
)
+
" and Content-Length was: "
+
request
.
getContentLength
()
+
"!"
;
return
"Posted "
+
body
.
get
(
"foo"
)
+
" and Content-Length was: "
+
request
.
getContentLength
()
+
"!"
;
}
}
@RequestMapping
(
value
=
"/deletewithbody"
,
method
=
RequestMethod
.
DELETE
)
@RequestMapping
(
value
=
"/deletewithbody"
,
method
=
RequestMethod
.
DELETE
)
...
@@ -374,8 +382,10 @@ public abstract class ZuulProxyTestBase {
...
@@ -374,8 +382,10 @@ public abstract class ZuulProxyTestBase {
public
String
slow
()
{
public
String
slow
()
{
try
{
try
{
Thread
.
sleep
(
80000
);
Thread
.
sleep
(
80000
);
}
catch
(
InterruptedException
e
)
{
}
e
.
printStackTrace
();
catch
(
InterruptedException
e
)
{
LOG
.
info
(
e
);
Thread
.
currentThread
().
interrupt
();
}
}
return
"slow"
;
return
"slow"
;
}
}
...
@@ -425,7 +435,6 @@ public abstract class ZuulProxyTestBase {
...
@@ -425,7 +435,6 @@ public abstract class ZuulProxyTestBase {
return
mapping
;
return
mapping
;
}
}
}
}
public
static
class
FallbackProvider
implements
ZuulFallbackProvider
{
public
static
class
FallbackProvider
implements
ZuulFallbackProvider
{
...
@@ -474,12 +483,14 @@ public abstract class ZuulProxyTestBase {
...
@@ -474,12 +483,14 @@ public abstract class ZuulProxyTestBase {
}
}
@Configuration
@Configuration
public
class
FormEncodedMessageConverterConfiguration
extends
WebMvcConfigurerAdapter
{
public
class
FormEncodedMessageConverterConfiguration
extends
WebMvcConfigurerAdapter
{
@Override
@Override
public
void
configureMessageConverters
(
List
<
HttpMessageConverter
<?>>
converters
)
{
public
void
configureMessageConverters
(
List
<
HttpMessageConverter
<?>>
converters
)
{
FormHttpMessageConverter
converter
=
new
FormHttpMessageConverter
();
FormHttpMessageConverter
converter
=
new
FormHttpMessageConverter
();
MediaType
mediaType
=
new
MediaType
(
"application"
,
"x-www-form-urlencoded"
,
Charset
.
forName
(
"UTF-8"
));
MediaType
mediaType
=
new
MediaType
(
"application"
,
"x-www-form-urlencoded"
,
Charset
.
forName
(
"UTF-8"
));
converter
.
setSupportedMediaTypes
(
Arrays
.
asList
(
mediaType
));
converter
.
setSupportedMediaTypes
(
Arrays
.
asList
(
mediaType
));
converters
.
add
(
converter
);
converters
.
add
(
converter
);
super
.
configureMessageConverters
(
converters
);
super
.
configureMessageConverters
(
converters
);
...
@@ -524,7 +535,8 @@ public abstract class ZuulProxyTestBase {
...
@@ -524,7 +535,8 @@ public abstract class ZuulProxyTestBase {
@Override
@Override
public
ResponseEntity
<
Map
<
String
,
Object
>>
error
(
HttpServletRequest
request
)
{
public
ResponseEntity
<
Map
<
String
,
Object
>>
error
(
HttpServletRequest
request
)
{
String
errorUri
=
(
String
)
request
.
getAttribute
(
"javax.servlet.error.request_uri"
);
String
errorUri
=
(
String
)
request
.
getAttribute
(
"javax.servlet.error.request_uri"
);
if
(
errorUri
!=
null
&&
errorUri
.
equals
(
this
.
uriToMatch
.
get
()))
{
if
(
errorUri
!=
null
&&
errorUri
.
equals
(
this
.
uriToMatch
.
get
()))
{
controllerUsed
.
set
(
true
);
controllerUsed
.
set
(
true
);
...
...
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