Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
apollo
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
Administrator
apollo
Commits
e95128d5
Commit
e95128d5
authored
Apr 22, 2016
by
Jason Song
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Server side config update push
parent
745d7ca1
Changes
25
Show whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
667 additions
and
167 deletions
+667
-167
apollo-adminservice/src/main/java/com/ctrip/apollo/adminservice/AdminServiceAutoConfiguration.java
...ip/apollo/adminservice/AdminServiceAutoConfiguration.java
+56
-0
apollo-adminservice/src/main/java/com/ctrip/apollo/adminservice/controller/ReleaseController.java
...rip/apollo/adminservice/controller/ReleaseController.java
+11
-0
apollo-adminservice/src/test/java/com/ctrip/apollo/adminservice/controller/ReleaseControllerTest.java
...apollo/adminservice/controller/ReleaseControllerTest.java
+45
-0
apollo-biz/pom.xml
apollo-biz/pom.xml
+4
-0
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/DummyMessageSender.java
...java/com/ctrip/apollo/biz/message/DummyMessageSender.java
+15
-0
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/MessageListener.java
...in/java/com/ctrip/apollo/biz/message/MessageListener.java
+8
-0
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/MessageSender.java
...main/java/com/ctrip/apollo/biz/message/MessageSender.java
+8
-0
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/RedisMessageSender.java
...java/com/ctrip/apollo/biz/message/RedisMessageSender.java
+26
-0
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/Topics.java
...iz/src/main/java/com/ctrip/apollo/biz/message/Topics.java
+8
-0
apollo-biz/src/main/java/com/ctrip/apollo/biz/service/ConfigService.java
...main/java/com/ctrip/apollo/biz/service/ConfigService.java
+0
-28
apollo-biz/src/test/java/com/ctrip/apollo/biz/message/RedisMessageSenderTest.java
.../com/ctrip/apollo/biz/message/RedisMessageSenderTest.java
+49
-0
apollo-biz/src/test/java/com/ctrip/apollo/biz/service/ConfigServiceTest.java
.../java/com/ctrip/apollo/biz/service/ConfigServiceTest.java
+13
-32
apollo-client/src/main/java/com/ctrip/apollo/internals/AbstractConfig.java
.../main/java/com/ctrip/apollo/internals/AbstractConfig.java
+1
-3
apollo-client/src/main/java/com/ctrip/apollo/internals/AbstractConfigRepository.java
.../com/ctrip/apollo/internals/AbstractConfigRepository.java
+1
-3
apollo-client/src/main/java/com/ctrip/apollo/internals/RemoteConfigRepository.java
...va/com/ctrip/apollo/internals/RemoteConfigRepository.java
+1
-1
apollo-client/src/main/java/com/ctrip/apollo/util/ExceptionUtil.java
...nt/src/main/java/com/ctrip/apollo/util/ExceptionUtil.java
+29
-4
apollo-client/src/test/java/com/ctrip/apollo/AllTests.java
apollo-client/src/test/java/com/ctrip/apollo/AllTests.java
+2
-1
apollo-client/src/test/java/com/ctrip/apollo/integration/ConfigIntegrationTest.java
...a/com/ctrip/apollo/integration/ConfigIntegrationTest.java
+14
-2
apollo-client/src/test/java/com/ctrip/apollo/util/ExceptionUtilTest.java
...rc/test/java/com/ctrip/apollo/util/ExceptionUtilTest.java
+50
-0
apollo-configservice/src/main/java/com/ctrip/apollo/configservice/ConfigServiceAutoConfiguration.java
.../apollo/configservice/ConfigServiceAutoConfiguration.java
+58
-0
apollo-configservice/src/main/java/com/ctrip/apollo/configservice/controller/ConfigController.java
...rip/apollo/configservice/controller/ConfigController.java
+60
-15
apollo-configservice/src/main/java/com/ctrip/apollo/configservice/controller/NotificationController.java
...ollo/configservice/controller/NotificationController.java
+51
-33
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/AllTests.java
...rc/test/java/com/ctrip/apollo/configservice/AllTests.java
+2
-1
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/controller/ConfigControllerTest.java
...apollo/configservice/controller/ConfigControllerTest.java
+71
-44
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/controller/NotificationControllerTest.java
.../configservice/controller/NotificationControllerTest.java
+84
-0
No files found.
apollo-adminservice/src/main/java/com/ctrip/apollo/adminservice/AdminServiceAutoConfiguration.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
adminservice
;
import
com.ctrip.apollo.biz.message.DummyMessageSender
;
import
com.ctrip.apollo.biz.message.MessageSender
;
import
com.ctrip.apollo.biz.message.RedisMessageSender
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.connection.jedis.JedisConnectionFactory
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Configuration
public
class
AdminServiceAutoConfiguration
{
@ConditionalOnProperty
(
value
=
"apollo.redis.enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
false
)
public
static
class
AdminRedisConfiguration
{
@Value
(
"${apollo.redis.host}"
)
private
String
host
;
@Value
(
"${apollo.redis.port}"
)
private
int
port
;
@Bean
public
JedisConnectionFactory
redisConnectionFactory
()
{
JedisConnectionFactory
factory
=
new
JedisConnectionFactory
();
factory
.
setHostName
(
host
);
factory
.
setPort
(
port
);
return
factory
;
}
@Bean
public
RedisTemplate
<
String
,
String
>
redisTemplate
(
RedisConnectionFactory
factory
)
{
StringRedisTemplate
template
=
new
StringRedisTemplate
(
factory
);
return
template
;
}
@Bean
public
MessageSender
redisMessageSender
(
RedisTemplate
<
String
,
String
>
redisTemplate
)
{
return
new
RedisMessageSender
(
redisTemplate
);
}
}
@Configuration
@ConditionalOnProperty
(
value
=
"apollo.redis.enabled"
,
havingValue
=
"false"
,
matchIfMissing
=
true
)
public
static
class
ConfigDefaultConfiguration
{
@Bean
public
MessageSender
defaultMessageSender
()
{
return
new
DummyMessageSender
();
}
}
}
apollo-adminservice/src/main/java/com/ctrip/apollo/adminservice/controller/ReleaseController.java
View file @
e95128d5
...
@@ -12,6 +12,8 @@ import org.springframework.web.bind.annotation.RestController;
...
@@ -12,6 +12,8 @@ import org.springframework.web.bind.annotation.RestController;
import
com.ctrip.apollo.biz.entity.Namespace
;
import
com.ctrip.apollo.biz.entity.Namespace
;
import
com.ctrip.apollo.biz.entity.Release
;
import
com.ctrip.apollo.biz.entity.Release
;
import
com.ctrip.apollo.biz.message.MessageSender
;
import
com.ctrip.apollo.biz.message.Topics
;
import
com.ctrip.apollo.biz.service.ConfigService
;
import
com.ctrip.apollo.biz.service.ConfigService
;
import
com.ctrip.apollo.biz.service.NamespaceService
;
import
com.ctrip.apollo.biz.service.NamespaceService
;
import
com.ctrip.apollo.biz.service.ReleaseService
;
import
com.ctrip.apollo.biz.service.ReleaseService
;
...
@@ -32,6 +34,9 @@ public class ReleaseController {
...
@@ -32,6 +34,9 @@ public class ReleaseController {
@Autowired
@Autowired
private
NamespaceService
namespaceService
;
private
NamespaceService
namespaceService
;
@Autowired
private
MessageSender
messageSender
;
@RequestMapping
(
"/release/{releaseId}"
)
@RequestMapping
(
"/release/{releaseId}"
)
public
ReleaseDTO
get
(
@PathVariable
(
"releaseId"
)
long
releaseId
)
{
public
ReleaseDTO
get
(
@PathVariable
(
"releaseId"
)
long
releaseId
)
{
Release
release
=
releaseService
.
findOne
(
releaseId
);
Release
release
=
releaseService
.
findOne
(
releaseId
);
...
@@ -73,6 +78,12 @@ public class ReleaseController {
...
@@ -73,6 +78,12 @@ public class ReleaseController {
clusterName
,
namespaceName
));
clusterName
,
namespaceName
));
}
}
Release
release
=
releaseService
.
buildRelease
(
name
,
comment
,
namespace
,
user
.
getUsername
());
Release
release
=
releaseService
.
buildRelease
(
name
,
comment
,
namespace
,
user
.
getUsername
());
messageSender
.
sendMessage
(
assembleKey
(
appId
,
clusterName
,
namespaceName
),
Topics
.
APOLLO_RELEASE_TOPIC
);
return
BeanUtils
.
transfrom
(
ReleaseDTO
.
class
,
release
);
return
BeanUtils
.
transfrom
(
ReleaseDTO
.
class
,
release
);
}
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
)
{
return
String
.
format
(
"%s-%s-%s"
,
appId
,
cluster
,
namespace
);
}
}
}
apollo-adminservice/src/test/java/com/ctrip/apollo/adminservice/controller/ReleaseControllerTest.java
View file @
e95128d5
...
@@ -9,12 +9,19 @@ import org.springframework.beans.factory.annotation.Autowired;
...
@@ -9,12 +9,19 @@ import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.core.userdetails.UserDetails
;
import
org.springframework.test.context.jdbc.Sql
;
import
org.springframework.test.context.jdbc.Sql
;
import
org.springframework.test.context.jdbc.Sql.ExecutionPhase
;
import
org.springframework.test.context.jdbc.Sql.ExecutionPhase
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
org.springframework.util.LinkedMultiValueMap
;
import
org.springframework.util.LinkedMultiValueMap
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.util.MultiValueMap
;
import
com.ctrip.apollo.biz.entity.Namespace
;
import
com.ctrip.apollo.biz.message.MessageSender
;
import
com.ctrip.apollo.biz.message.Topics
;
import
com.ctrip.apollo.biz.repository.ReleaseRepository
;
import
com.ctrip.apollo.biz.repository.ReleaseRepository
;
import
com.ctrip.apollo.biz.service.NamespaceService
;
import
com.ctrip.apollo.biz.service.ReleaseService
;
import
com.ctrip.apollo.core.dto.AppDTO
;
import
com.ctrip.apollo.core.dto.AppDTO
;
import
com.ctrip.apollo.core.dto.ClusterDTO
;
import
com.ctrip.apollo.core.dto.ClusterDTO
;
import
com.ctrip.apollo.core.dto.ItemDTO
;
import
com.ctrip.apollo.core.dto.ItemDTO
;
...
@@ -22,6 +29,11 @@ import com.ctrip.apollo.core.dto.NamespaceDTO;
...
@@ -22,6 +29,11 @@ import com.ctrip.apollo.core.dto.NamespaceDTO;
import
com.ctrip.apollo.core.dto.ReleaseDTO
;
import
com.ctrip.apollo.core.dto.ReleaseDTO
;
import
com.google.gson.Gson
;
import
com.google.gson.Gson
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
public
class
ReleaseControllerTest
extends
AbstractControllerTest
{
public
class
ReleaseControllerTest
extends
AbstractControllerTest
{
@Autowired
@Autowired
...
@@ -78,4 +90,37 @@ public class ReleaseControllerTest extends AbstractControllerTest {
...
@@ -78,4 +90,37 @@ public class ReleaseControllerTest extends AbstractControllerTest {
Gson
gson
=
new
Gson
();
Gson
gson
=
new
Gson
();
Assert
.
assertEquals
(
gson
.
toJson
(
configurations
),
release
.
getConfigurations
());
Assert
.
assertEquals
(
gson
.
toJson
(
configurations
),
release
.
getConfigurations
());
}
}
@Test
public
void
testMessageSendAfterBuildRelease
()
throws
Exception
{
String
someAppId
=
"someAppId"
;
String
someNamespaceName
=
"someNamespace"
;
String
someCluster
=
"someCluster"
;
String
someName
=
"someName"
;
String
someComment
=
"someComment"
;
String
someUserName
=
"someUser"
;
NamespaceService
someNamespaceService
=
mock
(
NamespaceService
.
class
);
ReleaseService
someReleaseService
=
mock
(
ReleaseService
.
class
);
MessageSender
someMessageSender
=
mock
(
MessageSender
.
class
);
Namespace
someNamespace
=
mock
(
Namespace
.
class
);
UserDetails
someUser
=
mock
(
UserDetails
.
class
);
ReleaseController
releaseController
=
new
ReleaseController
();
ReflectionTestUtils
.
setField
(
releaseController
,
"releaseService"
,
someReleaseService
);
ReflectionTestUtils
.
setField
(
releaseController
,
"namespaceService"
,
someNamespaceService
);
ReflectionTestUtils
.
setField
(
releaseController
,
"messageSender"
,
someMessageSender
);
when
(
someNamespaceService
.
findOne
(
someAppId
,
someCluster
,
someNamespaceName
))
.
thenReturn
(
someNamespace
);
when
(
someUser
.
getUsername
()).
thenReturn
(
someUserName
);
releaseController
.
buildRelease
(
someAppId
,
someCluster
,
someNamespaceName
,
someName
,
someComment
,
someUser
);
verify
(
someMessageSender
,
times
(
1
))
.
sendMessage
(
String
.
format
(
"%s-%s-%s"
,
someAppId
,
someCluster
,
someNamespaceName
),
Topics
.
APOLLO_RELEASE_TOPIC
);
}
}
}
apollo-biz/pom.xml
View file @
e95128d5
...
@@ -22,6 +22,10 @@
...
@@ -22,6 +22,10 @@
<groupId>
org.springframework.boot
</groupId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-data-jpa
</artifactId>
<artifactId>
spring-boot-starter-data-jpa
</artifactId>
</dependency>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-redis
</artifactId>
</dependency>
<dependency>
<dependency>
<groupId>
mysql
</groupId>
<groupId>
mysql
</groupId>
<artifactId>
mysql-connector-java
</artifactId>
<artifactId>
mysql-connector-java
</artifactId>
...
...
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/DummyMessageSender.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
biz
.
message
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
DummyMessageSender
implements
MessageSender
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
DummyMessageSender
.
class
);
@Override
public
void
sendMessage
(
String
message
,
String
channel
)
{
logger
.
warn
(
"No message sender available! message: {}, channel: {}"
,
message
,
channel
);
}
}
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/MessageListener.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
biz
.
message
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
interface
MessageListener
{
void
handleMessage
(
String
message
,
String
channel
);
}
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/MessageSender.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
biz
.
message
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
interface
MessageSender
{
void
sendMessage
(
String
message
,
String
channel
);
}
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/RedisMessageSender.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
biz
.
message
;
import
org.springframework.data.redis.core.RedisTemplate
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
RedisMessageSender
implements
MessageSender
{
private
RedisTemplate
<
String
,
String
>
redisTemplate
;
public
RedisMessageSender
(
RedisTemplate
<
String
,
String
>
redisTemplate
)
{
this
.
redisTemplate
=
redisTemplate
;
}
@Override
public
void
sendMessage
(
String
message
,
String
channel
)
{
try
{
redisTemplate
.
convertAndSend
(
channel
,
message
);
}
catch
(
Throwable
ex
)
{
}
finally
{
}
}
}
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/Topics.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
biz
.
message
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
Topics
{
public
static
final
String
APOLLO_RELEASE_TOPIC
=
"apollo-release"
;
}
apollo-biz/src/main/java/com/ctrip/apollo/biz/service/ConfigService.java
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
biz
.
service
;
package
com
.
ctrip
.
apollo
.
biz
.
service
;
import
com.google.gson.Gson
;
import
com.google.gson.reflect.TypeToken
;
import
com.ctrip.apollo.biz.entity.Release
;
import
com.ctrip.apollo.biz.entity.Release
;
import
com.ctrip.apollo.biz.repository.ReleaseRepository
;
import
com.ctrip.apollo.biz.repository.ReleaseRepository
;
import
com.ctrip.apollo.core.dto.ApolloConfig
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
java.lang.reflect.Type
;
import
java.util.Map
;
/**
/**
* Config Service
* Config Service
*
*
...
@@ -24,30 +17,9 @@ public class ConfigService {
...
@@ -24,30 +17,9 @@ public class ConfigService {
@Autowired
@Autowired
private
ReleaseRepository
releaseRepository
;
private
ReleaseRepository
releaseRepository
;
private
Gson
gson
=
new
Gson
();
private
Type
configurationTypeReference
=
new
TypeToken
<
Map
<
String
,
String
>>()
{}.
getType
();
public
Release
findRelease
(
String
appId
,
String
clusterName
,
String
namespaceName
)
{
public
Release
findRelease
(
String
appId
,
String
clusterName
,
String
namespaceName
)
{
Release
release
=
releaseRepository
.
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
Release
release
=
releaseRepository
.
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
appId
,
clusterName
,
namespaceName
);
appId
,
clusterName
,
namespaceName
);
return
release
;
return
release
;
}
}
/**
* Load configuration from database
*/
public
ApolloConfig
loadConfig
(
Release
release
)
{
if
(
release
==
null
)
{
return
null
;
}
ApolloConfig
config
=
new
ApolloConfig
(
release
.
getAppId
(),
release
.
getClusterName
(),
release
.
getNamespaceName
(),
String
.
valueOf
(
release
.
getId
()));
config
.
setConfigurations
(
transformConfigurationToMap
(
release
.
getConfigurations
()));
return
config
;
}
Map
<
String
,
String
>
transformConfigurationToMap
(
String
configurations
)
{
return
gson
.
fromJson
(
configurations
,
configurationTypeReference
);
}
}
}
apollo-biz/src/test/java/com/ctrip/apollo/biz/message/RedisMessageSenderTest.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
biz
.
message
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.Mock
;
import
org.mockito.runners.MockitoJUnitRunner
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
static
org
.
mockito
.
Mockito
.
doThrow
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
RedisMessageSenderTest
{
@Mock
private
RedisTemplate
<
String
,
String
>
redisTemplate
;
private
RedisMessageSender
redisMessageSender
;
@Before
public
void
setUp
()
throws
Exception
{
redisMessageSender
=
new
RedisMessageSender
(
redisTemplate
);
}
@Test
public
void
testSendMessage
()
throws
Exception
{
String
someMessage
=
"someMessage"
;
String
someChannel
=
"someChannel"
;
redisMessageSender
.
sendMessage
(
someMessage
,
someChannel
);
verify
(
redisTemplate
,
times
(
1
)).
convertAndSend
(
someChannel
,
someMessage
);
}
@Test
public
void
testSendMessageWithError
()
throws
Exception
{
String
someMessage
=
"someMessage"
;
String
someChannel
=
"someChannel"
;
doThrow
(
new
RuntimeException
()).
when
(
redisTemplate
).
convertAndSend
(
someChannel
,
someMessage
);
redisMessageSender
.
sendMessage
(
someMessage
,
someChannel
);
}
}
apollo-biz/src/test/java/com/ctrip/apollo/biz/service/ConfigServiceTest.java
View file @
e95128d5
...
@@ -39,25 +39,28 @@ public class ConfigServiceTest {
...
@@ -39,25 +39,28 @@ public class ConfigServiceTest {
}
}
@Test
@Test
public
void
test
LoadConfig
()
throws
Exception
{
public
void
test
FindRelease
()
throws
Exception
{
String
someAppId
=
"1"
;
String
someAppId
=
"1"
;
String
someClusterName
=
"someClusterName"
;
String
someClusterName
=
"someClusterName"
;
String
some
GroupName
=
"someGroup
Name"
;
String
some
NamespaceName
=
"someNamespace
Name"
;
String
someReleaseId
=
"1"
;
String
someReleaseId
=
"1"
;
String
someValidConfiguration
=
"{\"apollo.bar\": \"foo\"}"
;
String
someValidConfiguration
=
"{\"apollo.bar\": \"foo\"}"
;
Release
someRelease
=
assembleRelease
(
someReleaseId
,
someAppId
,
someClusterName
,
some
Group
Name
,
Release
someRelease
=
assembleRelease
(
someReleaseId
,
someAppId
,
someClusterName
,
some
Namespace
Name
,
someValidConfiguration
);
someValidConfiguration
);
when
(
releaseRepository
.
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
someAppId
,
when
(
releaseRepository
.
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
someAppId
,
someClusterName
,
some
Group
Name
)).
thenReturn
(
someRelease
);
someClusterName
,
some
Namespace
Name
)).
thenReturn
(
someRelease
);
ApolloConfig
result
=
configService
.
loadConfig
(
someReleas
e
);
Release
result
=
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceNam
e
);
verify
(
releaseRepository
,
times
(
1
))
.
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
someAppId
,
someClusterName
,
someNamespaceName
);
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someClusterName
,
result
.
getCluster
());
assertEquals
(
someClusterName
,
result
.
getCluster
Name
());
assertEquals
(
someReleaseId
,
result
.
getReleaseId
(
));
assertEquals
(
someReleaseId
,
String
.
valueOf
(
result
.
getId
()
));
assertEquals
(
"foo"
,
result
.
getConfigurations
().
get
(
"apollo.bar"
));
assertEquals
(
someValidConfiguration
,
result
.
getConfigurations
(
));
}
}
@Test
@Test
...
@@ -68,8 +71,8 @@ public class ConfigServiceTest {
...
@@ -68,8 +71,8 @@ public class ConfigServiceTest {
when
(
releaseRepository
.
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
someAppId
,
when
(
releaseRepository
.
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
null
);
someClusterName
,
someNamespaceName
)).
thenReturn
(
null
);
Release
someRelease
=
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
);
ApolloConfig
result
=
configService
.
loadConfig
(
someReleas
e
);
Release
result
=
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceNam
e
);
assertNull
(
result
);
assertNull
(
result
);
verify
(
releaseRepository
,
times
(
1
)).
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
verify
(
releaseRepository
,
times
(
1
)).
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
...
@@ -87,26 +90,4 @@ public class ConfigServiceTest {
...
@@ -87,26 +90,4 @@ public class ConfigServiceTest {
return
release
;
return
release
;
}
}
@Test
public
void
testTransformConfigurationToMapSuccessful
()
throws
Exception
{
String
someValidConfiguration
=
"{\"apollo.bar\": \"foo\"}"
;
Map
<
String
,
String
>
someMap
=
Maps
.
newHashMap
();
someMap
.
put
(
"apollo.bar"
,
"foo"
);
Map
<
String
,
String
>
result
=
configService
.
transformConfigurationToMap
(
someValidConfiguration
);
assertEquals
(
someMap
,
result
);
}
@Test
(
expected
=
JsonSyntaxException
.
class
)
public
void
testTransformConfigurationToMapFailed
()
throws
Exception
{
String
someInvalidConfiguration
=
"xxx"
;
Map
<
String
,
String
>
result
=
configService
.
transformConfigurationToMap
(
someInvalidConfiguration
);
assertTrue
(
result
.
isEmpty
());
}
}
}
apollo-client/src/main/java/com/ctrip/apollo/internals/AbstractConfig.java
View file @
e95128d5
...
@@ -9,7 +9,6 @@ import com.ctrip.apollo.ConfigChangeListener;
...
@@ -9,7 +9,6 @@ import com.ctrip.apollo.ConfigChangeListener;
import
com.ctrip.apollo.enums.PropertyChangeType
;
import
com.ctrip.apollo.enums.PropertyChangeType
;
import
com.ctrip.apollo.model.ConfigChange
;
import
com.ctrip.apollo.model.ConfigChange
;
import
com.ctrip.apollo.model.ConfigChangeEvent
;
import
com.ctrip.apollo.model.ConfigChangeEvent
;
import
com.ctrip.apollo.util.ExceptionUtil
;
import
com.dianping.cat.Cat
;
import
com.dianping.cat.Cat
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
...
@@ -39,8 +38,7 @@ public abstract class AbstractConfig implements Config {
...
@@ -39,8 +38,7 @@ public abstract class AbstractConfig implements Config {
listener
.
onChange
(
changeEvent
);
listener
.
onChange
(
changeEvent
);
}
catch
(
Throwable
ex
)
{
}
catch
(
Throwable
ex
)
{
Cat
.
logError
(
ex
);
Cat
.
logError
(
ex
);
logger
.
error
(
"Failed to invoke config change listener {}"
,
listener
.
getClass
(),
ExceptionUtil
logger
.
error
(
"Failed to invoke config change listener {}"
,
listener
.
getClass
(),
ex
);
.
getDetailMessage
(
ex
));
}
}
}
}
}
}
...
...
apollo-client/src/main/java/com/ctrip/apollo/internals/AbstractConfigRepository.java
View file @
e95128d5
...
@@ -49,9 +49,7 @@ public abstract class AbstractConfigRepository implements ConfigRepository {
...
@@ -49,9 +49,7 @@ public abstract class AbstractConfigRepository implements ConfigRepository {
listener
.
onRepositoryChange
(
namespace
,
newProperties
);
listener
.
onRepositoryChange
(
namespace
,
newProperties
);
}
catch
(
Throwable
ex
)
{
}
catch
(
Throwable
ex
)
{
Cat
.
logError
(
ex
);
Cat
.
logError
(
ex
);
logger
.
error
(
"Failed to invoke repository change listener {}"
,
listener
.
getClass
(),
logger
.
error
(
"Failed to invoke repository change listener {}"
,
listener
.
getClass
(),
ex
);
ExceptionUtil
.
getDetailMessage
(
ex
));
}
}
}
}
}
}
...
...
apollo-client/src/main/java/com/ctrip/apollo/internals/RemoteConfigRepository.java
View file @
e95128d5
...
@@ -264,7 +264,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
...
@@ -264,7 +264,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
transaction
.
addData
(
"StatusCode"
,
response
.
getStatusCode
());
transaction
.
addData
(
"StatusCode"
,
response
.
getStatusCode
());
transaction
.
setStatus
(
Message
.
SUCCESS
);
transaction
.
setStatus
(
Message
.
SUCCESS
);
}
catch
(
Throwable
ex
)
{
}
catch
(
Throwable
ex
)
{
logger
.
warn
(
"Long polling failed for appId: {}, cluster: {}, namespace: {}"
,
logger
.
warn
(
"Long polling failed for appId: {}, cluster: {}, namespace: {}
, reason: {}
"
,
appId
,
cluster
,
m_namespace
,
ExceptionUtil
.
getDetailMessage
(
ex
));
appId
,
cluster
,
m_namespace
,
ExceptionUtil
.
getDetailMessage
(
ex
));
lastServiceDto
=
null
;
lastServiceDto
=
null
;
Cat
.
logError
(
ex
);
Cat
.
logError
(
ex
);
...
...
apollo-client/src/main/java/com/ctrip/apollo/util/ExceptionUtil.java
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
util
;
package
com
.
ctrip
.
apollo
.
util
;
import
com.google.common.base.Strings
;
import
com.google.common.collect.Lists
;
import
java.util.List
;
/**
/**
* @author Jason Song(song_s@ctrip.com)
* @author Jason Song(song_s@ctrip.com)
*/
*/
public
class
ExceptionUtil
{
public
class
ExceptionUtil
{
public
static
String
getDetailMessage
(
Throwable
ex
)
{
public
static
String
getDetailMessage
(
Throwable
ex
)
{
if
(
ex
==
null
)
{
if
(
ex
==
null
||
Strings
.
isNullOrEmpty
(
ex
.
getMessage
())
)
{
return
""
;
return
""
;
}
}
if
(
ex
.
getCause
()
!=
null
)
{
StringBuilder
builder
=
new
StringBuilder
(
ex
.
getMessage
());
return
String
.
format
(
"%s [Cause: %s]"
,
ex
.
getMessage
(),
getDetailMessage
(
ex
.
getCause
()));
List
<
Throwable
>
causes
=
Lists
.
newLinkedList
();
int
counter
=
0
;
Throwable
current
=
ex
;
//retrieve up to 10 causes
while
(
current
.
getCause
()
!=
null
&&
counter
<
10
)
{
Throwable
next
=
current
.
getCause
();
causes
.
add
(
next
);
current
=
next
;
counter
++;
}
for
(
Throwable
cause
:
causes
)
{
if
(
Strings
.
isNullOrEmpty
(
cause
.
getMessage
()))
{
counter
--;
continue
;
}
builder
.
append
(
" [Cause: "
).
append
(
cause
.
getMessage
());
}
}
return
ex
.
getMessage
();
builder
.
append
(
Strings
.
repeat
(
"]"
,
counter
));
return
builder
.
toString
();
}
}
}
}
apollo-client/src/test/java/com/ctrip/apollo/AllTests.java
View file @
e95128d5
...
@@ -10,6 +10,7 @@ import com.ctrip.apollo.internals.SimpleConfigTest;
...
@@ -10,6 +10,7 @@ import com.ctrip.apollo.internals.SimpleConfigTest;
import
com.ctrip.apollo.spi.DefaultConfigFactoryManagerTest
;
import
com.ctrip.apollo.spi.DefaultConfigFactoryManagerTest
;
import
com.ctrip.apollo.spi.DefaultConfigFactoryTest
;
import
com.ctrip.apollo.spi.DefaultConfigFactoryTest
;
import
com.ctrip.apollo.spi.DefaultConfigRegistryTest
;
import
com.ctrip.apollo.spi.DefaultConfigRegistryTest
;
import
com.ctrip.apollo.util.ExceptionUtilTest
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.junit.runners.Suite
;
import
org.junit.runners.Suite
;
...
@@ -20,7 +21,7 @@ import org.junit.runners.Suite.SuiteClasses;
...
@@ -20,7 +21,7 @@ import org.junit.runners.Suite.SuiteClasses;
ConfigServiceTest
.
class
,
DefaultConfigRegistryTest
.
class
,
DefaultConfigFactoryManagerTest
.
class
,
ConfigServiceTest
.
class
,
DefaultConfigRegistryTest
.
class
,
DefaultConfigFactoryManagerTest
.
class
,
DefaultConfigManagerTest
.
class
,
DefaultConfigTest
.
class
,
LocalFileConfigRepositoryTest
.
class
,
DefaultConfigManagerTest
.
class
,
DefaultConfigTest
.
class
,
LocalFileConfigRepositoryTest
.
class
,
RemoteConfigRepositoryTest
.
class
,
SimpleConfigTest
.
class
,
DefaultConfigFactoryTest
.
class
,
RemoteConfigRepositoryTest
.
class
,
SimpleConfigTest
.
class
,
DefaultConfigFactoryTest
.
class
,
ConfigIntegrationTest
.
class
ConfigIntegrationTest
.
class
,
ExceptionUtilTest
.
class
})
})
public
class
AllTests
{
public
class
AllTests
{
...
...
apollo-client/src/test/java/com/ctrip/apollo/integration/ConfigIntegrationTest.java
View file @
e95128d5
...
@@ -3,6 +3,7 @@ package com.ctrip.apollo.integration;
...
@@ -3,6 +3,7 @@ package com.ctrip.apollo.integration;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Maps
;
import
com.google.common.collect.Maps
;
import
com.google.common.util.concurrent.SettableFuture
;
import
com.ctrip.apollo.Config
;
import
com.ctrip.apollo.Config
;
import
com.ctrip.apollo.ConfigChangeListener
;
import
com.ctrip.apollo.ConfigChangeListener
;
...
@@ -194,6 +195,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
...
@@ -194,6 +195,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
Config
config
=
ConfigService
.
getConfig
();
Config
config
=
ConfigService
.
getConfig
();
final
List
<
ConfigChangeEvent
>
changeEvents
=
Lists
.
newArrayList
();
final
List
<
ConfigChangeEvent
>
changeEvents
=
Lists
.
newArrayList
();
final
SettableFuture
<
Boolean
>
refreshFinished
=
SettableFuture
.
create
();
config
.
addChangeListener
(
new
ConfigChangeListener
()
{
config
.
addChangeListener
(
new
ConfigChangeListener
()
{
AtomicInteger
counter
=
new
AtomicInteger
(
0
);
AtomicInteger
counter
=
new
AtomicInteger
(
0
);
...
@@ -208,12 +210,13 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
...
@@ -208,12 +210,13 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
assertEquals
(
anotherValue
,
changeEvent
.
getChange
(
someKey
).
getNewValue
());
assertEquals
(
anotherValue
,
changeEvent
.
getChange
(
someKey
).
getNewValue
());
// if there is any assertion failed above, this line won't be executed
// if there is any assertion failed above, this line won't be executed
changeEvents
.
add
(
changeEvent
);
changeEvents
.
add
(
changeEvent
);
refreshFinished
.
set
(
true
);
}
}
});
});
apolloConfig
.
getConfigurations
().
put
(
someKey
,
anotherValue
);
apolloConfig
.
getConfigurations
().
put
(
someKey
,
anotherValue
);
someRefreshTimeUnit
.
sleep
(
someRefreshInterval
*
2
);
refreshFinished
.
get
(
someRefreshInterval
*
5
,
someRefreshTimeUnit
);
assertThat
(
assertThat
(
"Change event's size should equal to one or there must be some assertion failed in change listener"
,
"Change event's size should equal to one or there must be some assertion failed in change listener"
,
...
@@ -242,9 +245,18 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
...
@@ -242,9 +245,18 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
Config
config
=
ConfigService
.
getConfig
();
Config
config
=
ConfigService
.
getConfig
();
assertEquals
(
someValue
,
config
.
getProperty
(
someKey
,
null
));
assertEquals
(
someValue
,
config
.
getProperty
(
someKey
,
null
));
final
SettableFuture
<
Boolean
>
longPollFinished
=
SettableFuture
.
create
();
config
.
addChangeListener
(
new
ConfigChangeListener
()
{
@Override
public
void
onChange
(
ConfigChangeEvent
changeEvent
)
{
longPollFinished
.
set
(
true
);
}
});
apolloConfig
.
getConfigurations
().
put
(
someKey
,
anotherValue
);
apolloConfig
.
getConfigurations
().
put
(
someKey
,
anotherValue
);
TimeUnit
.
MILLISECONDS
.
sleep
(
pollTimeoutInMS
*
3
);
longPollFinished
.
get
(
pollTimeoutInMS
*
10
,
TimeUnit
.
MILLISECONDS
);
assertEquals
(
anotherValue
,
config
.
getProperty
(
someKey
,
null
));
assertEquals
(
anotherValue
,
config
.
getProperty
(
someKey
,
null
));
...
...
apollo-client/src/test/java/com/ctrip/apollo/util/ExceptionUtilTest.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
util
;
import
org.junit.Test
;
import
static
org
.
junit
.
Assert
.*;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
ExceptionUtilTest
{
@Test
public
void
testGetDetailMessageWithNoCause
()
throws
Exception
{
String
someMessage
=
"some message"
;
Throwable
ex
=
new
Throwable
(
someMessage
);
assertEquals
(
someMessage
,
ExceptionUtil
.
getDetailMessage
(
ex
));
}
@Test
public
void
testGetDetailMessageWithCauses
()
throws
Exception
{
String
causeMsg1
=
"some cause"
;
String
causeMsg2
=
"another cause"
;
String
someMessage
=
"some message"
;
Throwable
cause2
=
new
Throwable
(
causeMsg2
);
Throwable
cause1
=
new
Throwable
(
causeMsg1
,
cause2
);
Throwable
ex
=
new
Throwable
(
someMessage
,
cause1
);
String
expected
=
someMessage
+
" [Cause: "
+
causeMsg1
+
" [Cause: "
+
causeMsg2
+
"]]"
;
assertEquals
(
expected
,
ExceptionUtil
.
getDetailMessage
(
ex
));
}
@Test
public
void
testGetDetailMessageWithCauseMessageNull
()
throws
Exception
{
String
someMessage
=
"some message"
;
Throwable
cause
=
new
Throwable
();
Throwable
ex
=
new
Throwable
(
someMessage
,
cause
);
assertEquals
(
someMessage
,
ExceptionUtil
.
getDetailMessage
(
ex
));
}
@Test
public
void
testGetDetailMessageWithNullMessage
()
throws
Exception
{
Throwable
ex
=
new
Throwable
();
assertEquals
(
""
,
ExceptionUtil
.
getDetailMessage
(
ex
));
assertEquals
(
""
,
ExceptionUtil
.
getDetailMessage
(
null
));
}
}
apollo-configservice/src/main/java/com/ctrip/apollo/configservice/ConfigServiceAutoConfiguration.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
configservice
;
import
com.ctrip.apollo.biz.message.Topics
;
import
com.ctrip.apollo.configservice.controller.NotificationController
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.connection.jedis.JedisConnectionFactory
;
import
org.springframework.data.redis.listener.ChannelTopic
;
import
org.springframework.data.redis.listener.RedisMessageListenerContainer
;
import
org.springframework.data.redis.listener.adapter.MessageListenerAdapter
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Configuration
public
class
ConfigServiceAutoConfiguration
{
@ConditionalOnProperty
(
value
=
"apollo.redis.enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
false
)
public
static
class
ConfigRedisConfiguration
{
@Value
(
"${apollo.redis.host}"
)
private
String
host
;
@Value
(
"${apollo.redis.port}"
)
private
int
port
;
@Bean
public
JedisConnectionFactory
redisConnectionFactory
()
{
JedisConnectionFactory
factory
=
new
JedisConnectionFactory
();
factory
.
setHostName
(
host
);
factory
.
setPort
(
port
);
return
factory
;
}
@Bean
public
RedisMessageListenerContainer
redisMessageListenerContainer
(
RedisConnectionFactory
factory
)
{
RedisMessageListenerContainer
container
=
new
RedisMessageListenerContainer
();
container
.
setConnectionFactory
(
factory
);
return
container
;
}
@Bean
public
ChannelTopic
apolloReleaseTopic
()
{
return
new
ChannelTopic
(
Topics
.
APOLLO_RELEASE_TOPIC
);
}
@Bean
public
MessageListenerAdapter
apolloMessageListener
(
RedisMessageListenerContainer
container
,
NotificationController
notification
,
ChannelTopic
topic
)
{
MessageListenerAdapter
adapter
=
new
MessageListenerAdapter
(
notification
);
container
.
addMessageListener
(
adapter
,
topic
);
return
adapter
;
}
}
}
apollo-configservice/src/main/java/com/ctrip/apollo/configservice/controller/ConfigController.java
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
import
com.google.common.base.Joiner
;
import
com.google.common.collect.FluentIterable
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Maps
;
import
com.google.gson.Gson
;
import
com.google.gson.reflect.TypeToken
;
import
com.ctrip.apollo.biz.entity.Release
;
import
com.ctrip.apollo.biz.entity.Release
;
import
com.ctrip.apollo.biz.service.ConfigService
;
import
com.ctrip.apollo.biz.service.ConfigService
;
import
com.ctrip.apollo.core.dto.ApolloConfig
;
import
com.ctrip.apollo.core.dto.ApolloConfig
;
...
@@ -12,6 +19,10 @@ import org.springframework.web.bind.annotation.RequestParam;
...
@@ -12,6 +19,10 @@ import org.springframework.web.bind.annotation.RequestParam;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.lang.reflect.Type
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
...
@@ -24,44 +35,78 @@ public class ConfigController {
...
@@ -24,44 +35,78 @@ public class ConfigController {
@Autowired
@Autowired
private
ConfigService
configService
;
private
ConfigService
configService
;
private
Gson
gson
=
new
Gson
();
private
Type
configurationTypeReference
=
new
TypeToken
<
Map
<
java
.
lang
.
String
,
java
.
lang
.
String
>>()
{
}.
getType
();
@RequestMapping
(
value
=
"/{appId}/{clusterName}"
,
method
=
RequestMethod
.
GET
)
@RequestMapping
(
value
=
"/{appId}/{clusterName}"
,
method
=
RequestMethod
.
GET
)
public
ApolloConfig
queryConfig
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
public
ApolloConfig
queryConfig
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
@RequestParam
(
value
=
"datacenter"
,
required
=
false
)
String
datacenter
,
@RequestParam
(
value
=
"releaseId"
,
defaultValue
=
"-1"
)
String
clientSideReleaseId
,
@RequestParam
(
value
=
"releaseId"
,
defaultValue
=
"-1"
)
String
clientSideReleaseId
,
HttpServletResponse
response
)
throws
IOException
{
HttpServletResponse
response
)
throws
IOException
{
//default namespace is appId
//default namespace is appId
return
this
.
queryConfig
(
appId
,
clusterName
,
appId
,
clientSideReleaseId
,
response
);
return
this
.
queryConfig
(
appId
,
clusterName
,
appId
,
datacenter
,
clientSideReleaseId
,
response
);
}
}
@RequestMapping
(
value
=
"/{appId}/{clusterName}/{namespace}"
,
method
=
RequestMethod
.
GET
)
@RequestMapping
(
value
=
"/{appId}/{clusterName}/{namespace}"
,
method
=
RequestMethod
.
GET
)
public
ApolloConfig
queryConfig
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
public
ApolloConfig
queryConfig
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
@PathVariable
String
namespace
,
@PathVariable
String
namespace
,
@RequestParam
(
value
=
"datacenter"
,
required
=
false
)
String
datacenter
,
@RequestParam
(
value
=
"releaseId"
,
defaultValue
=
"-1"
)
String
clientSideReleaseId
,
@RequestParam
(
value
=
"releaseId"
,
defaultValue
=
"-1"
)
String
clientSideReleaseId
,
HttpServletResponse
response
)
throws
IOException
{
HttpServletResponse
response
)
throws
IOException
{
Release
release
=
configService
.
findRelease
(
appId
,
clusterName
,
namespace
);
List
<
Release
>
releases
=
Lists
.
newLinkedList
();
//TODO if namespace != application, should also query config by namespace and DC(default if DC not found)?
//And if found, should merge config, as well as releaseId -> make releaseId a string?
Release
currentAppRelease
=
configService
.
findRelease
(
appId
,
clusterName
,
namespace
);
if
(
release
==
null
)
{
if
(
currentAppRelease
!=
null
)
{
releases
.
add
(
currentAppRelease
);
}
//if namespace is not appId itself, should check if it has its own configurations
if
(!
Objects
.
equals
(
appId
,
namespace
))
{
//TODO find id for this particular namespace, if not equal to current app id, then do more
if
(!
Objects
.
isNull
(
datacenter
))
{
//TODO load newAppId+datacenter+namespace configurations
}
//TODO if load from DC failed, then load newAppId+defaultCluster+namespace configurations
}
if
(
releases
.
isEmpty
())
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
,
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
,
String
.
format
(
String
.
format
(
"Could not load
version
with appId: %s, clusterName: %s, namespace: %s"
,
"Could not load
configurations
with appId: %s, clusterName: %s, namespace: %s"
,
appId
,
clusterName
,
namespace
));
appId
,
clusterName
,
namespace
));
return
null
;
return
null
;
}
}
if
(
String
.
valueOf
(
release
.
getId
()).
equals
(
clientSideReleaseId
))
{
String
mergedReleaseId
=
FluentIterable
.
from
(
releases
).
transform
(
input
->
String
.
valueOf
(
input
.
getId
())).
join
(
Joiner
.
on
(
"|"
));
if
(
mergedReleaseId
.
equals
(
clientSideReleaseId
))
{
// Client side configuration is the same with server side, return 304
// Client side configuration is the same with server side, return 304
response
.
setStatus
(
HttpServletResponse
.
SC_NOT_MODIFIED
);
response
.
setStatus
(
HttpServletResponse
.
SC_NOT_MODIFIED
);
return
null
;
return
null
;
}
}
ApolloConfig
apolloConfig
=
configService
.
loadConfig
(
release
);
ApolloConfig
apolloConfig
=
new
ApolloConfig
(
appId
,
clusterName
,
namespace
,
mergedReleaseId
);
apolloConfig
.
setConfigurations
(
mergeReleaseConfigurations
(
releases
));
if
(
apolloConfig
==
null
)
{
return
apolloConfig
;
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
,
String
.
format
(
"Could not load config with releaseId: %d, clusterName: %s"
,
release
.
getId
(),
clusterName
));
return
null
;
}
}
return
apolloConfig
;
/**
* Merge configurations of releases.
* Release in lower index override those in higher index
* @param releases
* @return
*/
Map
<
String
,
String
>
mergeReleaseConfigurations
(
List
<
Release
>
releases
)
{
Map
<
String
,
String
>
result
=
Maps
.
newHashMap
();
for
(
Release
release
:
Lists
.
reverse
(
releases
))
{
result
.
putAll
(
gson
.
fromJson
(
release
.
getConfigurations
(),
configurationTypeReference
));
}
}
return
result
;
}
}
}
apollo-configservice/src/main/java/com/ctrip/apollo/configservice/controller/NotificationController.java
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
import
com.google.common.base.Strings
;
import
com.google.common.collect.HashMultimap
;
import
com.google.common.collect.HashMultimap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Multimaps
;
import
com.google.common.collect.Multimaps
;
import
com.ctrip.apollo.biz.message.MessageListener
;
import
com.ctrip.apollo.biz.message.Topics
;
import
com.ctrip.apollo.core.dto.ApolloConfigNotification
;
import
com.ctrip.apollo.core.dto.ApolloConfigNotification
;
import
com.ctrip.apollo.core.utils.ApolloThreadFactory
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
...
@@ -15,11 +18,9 @@ import org.springframework.web.bind.annotation.RequestParam;
...
@@ -15,11 +18,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.context.request.async.DeferredResult
;
import
org.springframework.web.context.request.async.DeferredResult
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Objects
;
import
java.util.Random
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.ScheduledExecutorService
;
import
java.util.concurrent.TimeUnit
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
...
@@ -28,17 +29,11 @@ import javax.servlet.http.HttpServletResponse;
...
@@ -28,17 +29,11 @@ import javax.servlet.http.HttpServletResponse;
*/
*/
@RestController
@RestController
@RequestMapping
(
"/notifications"
)
@RequestMapping
(
"/notifications"
)
public
class
NotificationController
{
public
class
NotificationController
implements
MessageListener
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
NotificationController
.
class
);
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
NotificationController
.
class
);
private
final
static
long
TIMEOUT
=
120
*
60
*
1000
;
//120 MINUTES
private
final
static
long
TIMEOUT
=
360
*
60
*
1000
;
//6 hours
private
final
Multimap
<
String
,
DeferredResult
<
ApolloConfigNotification
>>
deferredResults
=
private
final
Multimap
<
String
,
DeferredResult
<
ApolloConfigNotification
>>
deferredResults
=
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.
create
());
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.
create
());
private
final
Multimap
<
DeferredResult
<
ApolloConfigNotification
>,
String
>
deferredResultReversed
=
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.
create
());
{
startRandomChange
();
}
@RequestMapping
(
method
=
RequestMethod
.
GET
)
@RequestMapping
(
method
=
RequestMethod
.
GET
)
public
DeferredResult
<
ApolloConfigNotification
>
pollNotification
(
public
DeferredResult
<
ApolloConfigNotification
>
pollNotification
(
...
@@ -53,41 +48,64 @@ public class NotificationController {
...
@@ -53,41 +48,64 @@ public class NotificationController {
namespace
=
appId
;
namespace
=
appId
;
}
}
List
<
String
>
watchedKeys
=
Lists
.
newArrayList
(
assembleKey
(
appId
,
cluster
,
namespace
));
//Listen more namespaces, since it's not the default namespace
if
(!
Objects
.
equals
(
appId
,
namespace
))
{
//TODO find id for this particular namespace, if not equal to current app id, then do more
if
(!
Objects
.
isNull
(
datacenter
))
{
//TODO add newAppId+datacenter+namespace to listened keys
}
//TODO add newAppId+defaultCluster+namespace to listened keys
}
DeferredResult
<
ApolloConfigNotification
>
deferredResult
=
DeferredResult
<
ApolloConfigNotification
>
deferredResult
=
new
DeferredResult
<>(
TIMEOUT
);
new
DeferredResult
<>(
TIMEOUT
);
String
key
=
assembleKey
(
appId
,
cluster
,
namespace
);
//register all keys
for
(
String
key
:
watchedKeys
)
{
this
.
deferredResults
.
put
(
key
,
deferredResult
);
this
.
deferredResults
.
put
(
key
,
deferredResult
);
//to record all the keys related to deferredResult
}
this
.
deferredResultReversed
.
put
(
deferredResult
,
key
);
final
String
finalNamespace
=
namespace
;
deferredResult
.
onCompletion
(()
->
{
deferredResult
.
onCompletion
(()
->
{
logger
.
info
(
"deferred result for {} {} {} completed"
,
appId
,
cluster
,
finalNamespace
);
//unregister all keys
for
(
String
key
:
watchedKeys
)
{
deferredResults
.
remove
(
key
,
deferredResult
);
deferredResults
.
remove
(
key
,
deferredResult
);
}
});
});
deferredResult
.
onTimeout
(()
->
{
deferredResult
.
onTimeout
(()
->
{
logger
.
info
(
"deferred result for {} {} {} timeout"
,
appId
,
cluster
,
finalNamespace
);
response
.
setStatus
(
HttpServletResponse
.
SC_NOT_MODIFIED
);
response
.
setStatus
(
HttpServletResponse
.
SC_NOT_MODIFIED
);
});
});
logger
.
info
(
"deferred result for {} {} {} returned"
,
appId
,
cluster
,
namespace
);
return
deferredResult
;
return
deferredResult
;
}
}
private
void
startRandomChange
()
{
Random
random
=
new
Random
();
ScheduledExecutorService
testService
=
Executors
.
newScheduledThreadPool
(
1
,
ApolloThreadFactory
.
create
(
"NotificationController"
,
true
));
testService
.
scheduleAtFixedRate
((
Runnable
)
()
->
deferredResults
.
entries
().
stream
().
filter
(
entry
->
random
.
nextBoolean
()).
forEach
(
entry
->
{
String
[]
keys
=
entry
.
getKey
().
split
(
"-"
);
entry
.
getValue
().
setResult
(
new
ApolloConfigNotification
(
keys
[
0
],
keys
[
1
],
keys
[
2
]));
}),
30
,
30
,
TimeUnit
.
SECONDS
);
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
)
{
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
)
{
return
String
.
format
(
"%s-%s-%s"
,
appId
,
cluster
,
namespace
);
return
String
.
format
(
"%s-%s-%s"
,
appId
,
cluster
,
namespace
);
}
}
@Override
public
void
handleMessage
(
String
message
,
String
channel
)
{
logger
.
info
(
"message received - channel: {}, message: {}"
,
channel
,
message
);
if
(!
Topics
.
APOLLO_RELEASE_TOPIC
.
equals
(
channel
)
||
Strings
.
isNullOrEmpty
(
message
))
{
return
;
}
String
[]
keys
=
message
.
split
(
"-"
);
//message should be appId-cluster-namespace
if
(
keys
.
length
!=
3
)
{
logger
.
error
(
"message format invalid - {}"
,
message
);
return
;
}
ApolloConfigNotification
notification
=
new
ApolloConfigNotification
(
keys
[
0
],
keys
[
1
],
keys
[
2
]);
Collection
<
DeferredResult
<
ApolloConfigNotification
>>
results
=
deferredResults
.
get
(
message
);
logger
.
info
(
"Notify {} clients for key {}"
,
results
.
size
(),
message
);
for
(
DeferredResult
<
ApolloConfigNotification
>
result
:
results
)
{
result
.
setResult
(
notification
);
}
}
}
}
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/AllTests.java
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
configservice
;
package
com
.
ctrip
.
apollo
.
configservice
;
import
com.ctrip.apollo.configservice.controller.ConfigControllerTest
;
import
com.ctrip.apollo.configservice.controller.ConfigControllerTest
;
import
com.ctrip.apollo.configservice.controller.NotificationControllerTest
;
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
;
@RunWith
(
Suite
.
class
)
@RunWith
(
Suite
.
class
)
@SuiteClasses
({
ConfigControllerTest
.
class
})
@SuiteClasses
({
ConfigControllerTest
.
class
,
NotificationControllerTest
.
class
})
public
class
AllTests
{
public
class
AllTests
{
}
}
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/controller/ConfigControllerTest.java
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Maps
;
import
com.google.gson.Gson
;
import
com.google.gson.JsonSyntaxException
;
import
com.ctrip.apollo.biz.entity.Release
;
import
com.ctrip.apollo.biz.entity.Release
;
import
com.ctrip.apollo.biz.service.ConfigService
;
import
com.ctrip.apollo.biz.service.ConfigService
;
import
com.ctrip.apollo.core.dto.ApolloConfig
;
import
com.ctrip.apollo.core.dto.ApolloConfig
;
...
@@ -11,15 +17,17 @@ import org.mockito.Mock;
...
@@ -11,15 +17,17 @@ import org.mockito.Mock;
import
org.mockito.runners.MockitoJUnitRunner
;
import
org.mockito.runners.MockitoJUnitRunner
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
java.util.Map
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNull
;
import
static
org
.
junit
.
Assert
.
assertNull
;
import
static
org
.
mockito
.
Mockito
.
any
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
mockito
.
Mockito
.
anyString
;
import
static
org
.
mockito
.
Mockito
.
anyString
;
import
static
org
.
mockito
.
Mockito
.
eq
;
import
static
org
.
mockito
.
Mockito
.
eq
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
never
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
import
static
org
.
mockito
.
Mockito
.
when
;
...
@@ -29,100 +37,119 @@ import static org.mockito.Mockito.when;
...
@@ -29,100 +37,119 @@ import static org.mockito.Mockito.when;
*/
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
ConfigControllerTest
{
public
class
ConfigControllerTest
{
private
ConfigController
configController
;
private
ConfigController
configController
;
@Mock
@Mock
private
ConfigService
configService
;
private
ConfigService
configService
;
private
String
someAppId
;
private
String
someClusterName
;
private
String
someNamespaceName
;
private
String
someDataCenter
;
private
String
someValidConfiguration
;
@Mock
private
Release
someRelease
;
@Before
@Before
public
void
setUp
()
throws
Exception
{
public
void
setUp
()
throws
Exception
{
configController
=
new
ConfigController
();
configController
=
new
ConfigController
();
ReflectionTestUtils
.
setField
(
configController
,
"configService"
,
configService
);
ReflectionTestUtils
.
setField
(
configController
,
"configService"
,
configService
);
someAppId
=
"1"
;
someClusterName
=
"someClusterName"
;
someNamespaceName
=
"someNamespaceName"
;
someDataCenter
=
"someDC"
;
someValidConfiguration
=
"{\"apollo.bar\": \"foo\"}"
;
when
(
someRelease
.
getConfigurations
()).
thenReturn
(
someValidConfiguration
);
}
}
@Test
@Test
public
void
testQueryConfig
()
throws
Exception
{
public
void
testQueryConfig
()
throws
Exception
{
ApolloConfig
someApolloConfig
=
mock
(
ApolloConfig
.
class
);
String
someAppId
=
"1"
;
String
someClusterName
=
"someClusterName"
;
String
someNamespaceName
=
"someNamespaceName"
;
long
someClientSideReleaseId
=
1
;
long
someClientSideReleaseId
=
1
;
long
someServerSideNewReleaseId
=
2
;
long
someServerSideNewReleaseId
=
2
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
Release
someRelease
=
mock
(
Release
.
class
);
when
(
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
))
when
(
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
))
.
thenReturn
(
someRelease
);
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getId
()).
thenReturn
(
someServerSideNewReleaseId
);
when
(
someRelease
.
getId
()).
thenReturn
(
someServerSideNewReleaseId
);
when
(
configService
.
loadConfig
(
someRelease
)).
thenReturn
(
someApolloConfig
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespaceName
,
String
.
valueOf
(
someClientSideReleaseId
),
someResponse
);
someNamespaceName
,
someDataCenter
,
String
.
valueOf
(
someClientSideReleaseId
),
someResponse
);
assertEquals
(
someApolloConfig
,
result
);
verify
(
configService
,
times
(
1
)).
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
);
verify
(
configService
,
times
(
1
)).
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
);
verify
(
configService
,
times
(
1
)).
loadConfig
(
someRelease
);
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someClusterName
,
result
.
getCluster
());
assertEquals
(
someNamespaceName
,
result
.
getNamespace
());
assertEquals
(
String
.
valueOf
(
someServerSideNewReleaseId
),
result
.
getReleaseId
());
}
}
@Test
@Test
public
void
testQueryConfigWithVersionNotFound
()
throws
Exception
{
public
void
testQueryConfigWithReleaseNotFound
()
throws
Exception
{
String
someAppId
=
"1"
;
String
someClusterName
=
"someClusterName"
;
String
someNamespaceName
=
"someNamespaceName"
;
long
someClientSideReleaseId
=
1
;
long
someClientSideReleaseId
=
1
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
when
(
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
null
);
when
(
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
null
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespaceName
,
String
.
valueOf
(
someClientSideReleaseId
),
someResponse
);
someNamespaceName
,
someDataCenter
,
String
.
valueOf
(
someClientSideReleaseId
),
someResponse
);
assertNull
(
result
);
assertNull
(
result
);
verify
(
someResponse
,
times
(
1
)).
sendError
(
eq
(
HttpServletResponse
.
SC_NOT_FOUND
),
anyString
());
verify
(
someResponse
,
times
(
1
)).
sendError
(
eq
(
HttpServletResponse
.
SC_NOT_FOUND
),
anyString
());
}
}
@Test
@Test
public
void
testQueryConfigWithApolloConfigNotFound
()
throws
Exception
{
public
void
testQueryConfigWithApolloConfigNotModified
()
throws
Exception
{
String
someAppId
=
"1"
;
String
someClusterName
=
"someClusterName"
;
String
someNamespaceName
=
"someNamespaceName"
;
long
someClientSideReleaseId
=
1
;
long
someClientSideReleaseId
=
1
;
long
someServerSide
NewReleaseId
=
2
;
long
someServerSide
ReleaseId
=
someClientSideReleaseId
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
Release
someRelease
=
mock
(
Release
.
class
);
when
(
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
))
when
(
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
))
.
thenReturn
(
someRelease
);
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getId
()).
thenReturn
(
someServerSideNewReleaseId
);
when
(
someRelease
.
getId
()).
thenReturn
(
someServerSideReleaseId
);
when
(
configService
.
loadConfig
(
someRelease
)).
thenReturn
(
null
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
ApolloConfig
someNamespaceName
,
String
.
valueOf
(
someClientSideReleaseId
),
someResponse
);
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespaceName
,
someDataCenter
,
String
.
valueOf
(
someClientSideReleaseId
),
someResponse
);
assertNull
(
result
);
assertNull
(
result
);
verify
(
someResponse
,
times
(
1
)).
se
ndError
(
eq
(
HttpServletResponse
.
SC_NOT_FOUND
),
anyString
()
);
verify
(
someResponse
,
times
(
1
)).
se
tStatus
(
HttpServletResponse
.
SC_NOT_MODIFIED
);
}
}
@Test
@Test
public
void
testQueryConfigWithApolloConfigNotModified
()
throws
Exception
{
public
void
testMergeConfigurations
()
throws
Exception
{
String
someAppId
=
"1"
;
Gson
gson
=
new
Gson
();
String
someClusterName
=
"someClusterName"
;
String
key1
=
"key1"
;
String
someNamespaceName
=
"someNamespaceName"
;
String
value1
=
"value1"
;
long
someClientSideReleaseId
=
1
;
String
anotherValue1
=
"anotherValue1"
;
long
someServerSideReleaseId
=
someClientSideReleaseId
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
Release
someRelease
=
mock
(
Release
.
class
);
when
(
configService
.
findRelease
(
someAppId
,
someClusterName
,
someNamespaceName
))
String
key2
=
"key2"
;
.
thenReturn
(
someRelease
);
String
value2
=
"value2"
;
when
(
someRelease
.
getId
()).
thenReturn
(
someServerSideReleaseId
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespaceName
,
Map
<
String
,
String
>
config
=
ImmutableMap
.
of
(
key1
,
anotherValue1
);
String
.
valueOf
(
someClientSideReleaseId
),
someResponse
);
Map
<
String
,
String
>
anotherConfig
=
ImmutableMap
.
of
(
key1
,
value1
,
key2
,
value2
);
assertNull
(
result
);
Release
releaseWithHighPriority
=
new
Release
();
verify
(
someResponse
,
times
(
1
)).
setStatus
(
HttpServletResponse
.
SC_NOT_MODIFIED
);
releaseWithHighPriority
.
setConfigurations
(
gson
.
toJson
(
config
));
verify
(
configService
,
never
()).
loadConfig
(
any
(
Release
.
class
));
Release
releaseWithLowPriority
=
new
Release
();
releaseWithLowPriority
.
setConfigurations
(
gson
.
toJson
(
anotherConfig
));
Map
<
String
,
String
>
result
=
configController
.
mergeReleaseConfigurations
(
Lists
.
newArrayList
(
releaseWithHighPriority
,
releaseWithLowPriority
));
assertEquals
(
2
,
result
.
keySet
().
size
());
assertEquals
(
anotherValue1
,
result
.
get
(
key1
));
assertEquals
(
value2
,
result
.
get
(
key2
));
}
@Test
(
expected
=
JsonSyntaxException
.
class
)
public
void
testTransformConfigurationToMapFailed
()
throws
Exception
{
String
someInvalidConfiguration
=
"xxx"
;
Release
someRelease
=
new
Release
();
someRelease
.
setConfigurations
(
someInvalidConfiguration
);
configController
.
mergeReleaseConfigurations
(
Lists
.
newArrayList
(
someRelease
));
}
}
}
}
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/controller/NotificationControllerTest.java
0 → 100644
View file @
e95128d5
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
import
com.google.common.collect.Multimap
;
import
com.ctrip.apollo.biz.message.Topics
;
import
com.ctrip.apollo.core.dto.ApolloConfigNotification
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.Mock
;
import
org.mockito.runners.MockitoJUnitRunner
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
org.springframework.web.context.request.async.DeferredResult
;
import
javax.servlet.http.HttpServletResponse
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
NotificationControllerTest
{
private
NotificationController
controller
;
private
String
someAppId
;
private
String
someCluster
;
private
String
someNamespace
;
private
String
someDataCenter
;
private
String
someReleaseId
;
@Mock
private
HttpServletResponse
response
;
private
Multimap
<
String
,
DeferredResult
<
ApolloConfigNotification
>>
deferredResults
;
@Before
public
void
setUp
()
throws
Exception
{
controller
=
new
NotificationController
();
someAppId
=
"someAppId"
;
someCluster
=
"someCluster"
;
someNamespace
=
"someNamespace"
;
someDataCenter
=
"someDC"
;
someReleaseId
=
"someRelease"
;
deferredResults
=
(
Multimap
<
String
,
DeferredResult
<
ApolloConfigNotification
>>)
ReflectionTestUtils
.
getField
(
controller
,
"deferredResults"
);
}
@Test
public
void
testPollNotificationWithDefaultNamespace
()
throws
Exception
{
someNamespace
=
someAppId
;
//default namespace
DeferredResult
<
ApolloConfigNotification
>
deferredResult
=
controller
.
pollNotification
(
someAppId
,
someCluster
,
someNamespace
,
someDataCenter
,
someReleaseId
,
response
);
String
key
=
String
.
format
(
"%s-%s-%s"
,
someAppId
,
someCluster
,
someNamespace
);
assertEquals
(
1
,
deferredResults
.
size
());
assertTrue
(
deferredResults
.
get
(
key
).
contains
(
deferredResult
));
}
@Test
public
void
testPollNotificationWithDefaultNamespaceAndHandleMessage
()
throws
Exception
{
someNamespace
=
someAppId
;
//default namespace
DeferredResult
<
ApolloConfigNotification
>
deferredResult
=
controller
.
pollNotification
(
someAppId
,
someCluster
,
someNamespace
,
someDataCenter
,
someReleaseId
,
response
);
String
key
=
String
.
format
(
"%s-%s-%s"
,
someAppId
,
someCluster
,
someNamespace
);
controller
.
handleMessage
(
key
,
Topics
.
APOLLO_RELEASE_TOPIC
);
ApolloConfigNotification
notification
=
(
ApolloConfigNotification
)
deferredResult
.
getResult
();
assertEquals
(
someAppId
,
notification
.
getAppId
());
assertEquals
(
someCluster
,
notification
.
getCluster
());
assertEquals
(
someNamespace
,
notification
.
getNamespace
());
}
}
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