Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
wrr-cat
apollo
提交
2a834828
apollo
项目概览
wrr-cat
/
apollo
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
apollo
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
2a834828
编写于
8月 27, 2017
作者:
张
张乐
提交者:
GitHub
8月 27, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #719 from nobodyiam/configservice-cache-merge
Config service cache and namespace name normalization
上级
f68cb458
699009f8
变更
44
展开全部
显示空白变更内容
内联
并排
Showing
44 changed file
with
2363 addition
and
500 deletion
+2363
-500
apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/NamespaceBranchController.java
...lo/adminservice/controller/NamespaceBranchController.java
+3
-0
apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ReleaseController.java
...ork/apollo/adminservice/controller/ReleaseController.java
+2
-0
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java
...java/com/ctrip/framework/apollo/biz/config/BizConfig.java
+35
-16
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/message/DatabaseMessageSender.java
...p/framework/apollo/biz/message/DatabaseMessageSender.java
+1
-0
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/message/ReleaseMessageScanner.java
...p/framework/apollo/biz/message/ReleaseMessageScanner.java
+14
-34
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/NamespaceService.java
.../ctrip/framework/apollo/biz/service/NamespaceService.java
+12
-1
apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/message/DatabaseMessageSenderTest.java
...amework/apollo/biz/message/DatabaseMessageSenderTest.java
+15
-0
apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/message/ReleaseMessageScannerTest.java
...amework/apollo/biz/message/ReleaseMessageScannerTest.java
+4
-3
apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigLongPollService.java
...amework/apollo/internals/RemoteConfigLongPollService.java
+60
-33
apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java
...ip/framework/apollo/internals/RemoteConfigRepository.java
+18
-7
apollo-client/src/test/java/com/ctrip/framework/apollo/internals/RemoteConfigLongPollServiceTest.java
...ork/apollo/internals/RemoteConfigLongPollServiceTest.java
+136
-10
apollo-client/src/test/java/com/ctrip/framework/apollo/internals/RemoteConfigRepositoryTest.java
...ramework/apollo/internals/RemoteConfigRepositoryTest.java
+39
-5
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAutoConfiguration.java
.../apollo/configservice/ConfigServiceAutoConfiguration.java
+19
-0
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigController.java
...ork/apollo/configservice/controller/ConfigController.java
+61
-95
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileController.java
...apollo/configservice/controller/ConfigFileController.java
+3
-1
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationController.java
...ollo/configservice/controller/NotificationController.java
+1
-0
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationControllerV2.java
...lo/configservice/controller/NotificationControllerV2.java
+60
-36
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/AppNamespaceServiceWithCache.java
...o/configservice/service/AppNamespaceServiceWithCache.java
+27
-6
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/AbstractConfigService.java
...o/configservice/service/config/AbstractConfigService.java
+87
-0
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/ConfigService.java
...rk/apollo/configservice/service/config/ConfigService.java
+26
-0
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/ConfigServiceWithCache.java
.../configservice/service/config/ConfigServiceWithCache.java
+190
-0
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/DefaultConfigService.java
...lo/configservice/service/config/DefaultConfigService.java
+36
-0
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/util/NamespaceUtil.java
...ip/framework/apollo/configservice/util/NamespaceUtil.java
+21
-0
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/wrapper/CaseInsensitiveMapWrapper.java
...ollo/configservice/wrapper/CaseInsensitiveMapWrapper.java
+26
-0
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/wrapper/DeferredResultWrapper.java
...k/apollo/configservice/wrapper/DeferredResultWrapper.java
+69
-0
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/AllTests.java
...va/com/ctrip/framework/apollo/configservice/AllTests.java
+5
-1
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigControllerTest.java
...apollo/configservice/controller/ConfigControllerTest.java
+98
-181
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileControllerTest.java
...lo/configservice/controller/ConfigFileControllerTest.java
+6
-5
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/NotificationControllerV2Test.java
...onfigservice/controller/NotificationControllerV2Test.java
+45
-20
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/AbstractBaseIntegrationTest.java
...onfigservice/integration/AbstractBaseIntegrationTest.java
+17
-0
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/ConfigControllerIntegrationTest.java
...gservice/integration/ConfigControllerIntegrationTest.java
+92
-0
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/ConfigFileControllerIntegrationTest.java
...vice/integration/ConfigFileControllerIntegrationTest.java
+82
-0
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/NotificationControllerIntegrationTest.java
...ce/integration/NotificationControllerIntegrationTest.java
+4
-0
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/NotificationControllerV2IntegrationTest.java
.../integration/NotificationControllerV2IntegrationTest.java
+341
-36
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/service/AppNamespaceServiceWithCacheTest.java
...nfigservice/service/AppNamespaceServiceWithCacheTest.java
+62
-6
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/service/config/ConfigServiceWithCacheTest.java
...figservice/service/config/ConfigServiceWithCacheTest.java
+287
-0
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/service/config/DefaultConfigServiceTest.java
...onfigservice/service/config/DefaultConfigServiceTest.java
+142
-0
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/util/NamespaceUtilTest.java
...ramework/apollo/configservice/util/NamespaceUtilTest.java
+65
-0
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/wrapper/CaseInsensitiveMapWrapperTest.java
.../configservice/wrapper/CaseInsensitiveMapWrapperTest.java
+67
-0
apollo-core/src/main/java/com/ctrip/framework/apollo/core/ConfigConsts.java
...in/java/com/ctrip/framework/apollo/core/ConfigConsts.java
+1
-0
apollo-core/src/main/java/com/ctrip/framework/apollo/core/dto/ApolloConfigNotification.java
...p/framework/apollo/core/dto/ApolloConfigNotification.java
+18
-2
apollo-core/src/main/java/com/ctrip/framework/apollo/core/dto/ApolloNotificationMessages.java
...framework/apollo/core/dto/ApolloNotificationMessages.java
+64
-0
scripts/sql-docker/apolloconfigdb.sql
scripts/sql-docker/apolloconfigdb.sql
+1
-1
scripts/sql/apolloconfigdb.sql
scripts/sql/apolloconfigdb.sql
+1
-1
未找到文件。
apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/NamespaceBranchController.java
浏览文件 @
2a834828
...
...
@@ -15,6 +15,7 @@ import com.ctrip.framework.apollo.common.utils.BeanUtils;
import
com.ctrip.framework.apollo.common.utils.GrayReleaseRuleItemTransformer
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
...
...
@@ -70,6 +71,7 @@ public class NamespaceBranchController {
return
ruleDTO
;
}
@Transactional
@RequestMapping
(
value
=
"/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules"
,
method
=
RequestMethod
.
PUT
)
public
void
updateBranchGrayRules
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
@PathVariable
String
namespaceName
,
@PathVariable
String
branchName
,
...
...
@@ -87,6 +89,7 @@ public class NamespaceBranchController {
Topics
.
APOLLO_RELEASE_TOPIC
);
}
@Transactional
@RequestMapping
(
value
=
"/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}"
,
method
=
RequestMethod
.
DELETE
)
public
void
deleteBranch
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
@PathVariable
String
namespaceName
,
@PathVariable
String
branchName
,
...
...
apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ReleaseController.java
浏览文件 @
2a834828
...
...
@@ -94,6 +94,7 @@ public class ReleaseController {
return
BeanUtils
.
transfrom
(
ReleaseDTO
.
class
,
release
);
}
@Transactional
@RequestMapping
(
path
=
"/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases"
,
method
=
RequestMethod
.
POST
)
public
ReleaseDTO
publish
(
@PathVariable
(
"appId"
)
String
appId
,
@PathVariable
(
"clusterName"
)
String
clusterName
,
...
...
@@ -160,6 +161,7 @@ public class ReleaseController {
}
@Transactional
@RequestMapping
(
path
=
"/releases/{releaseId}/rollback"
,
method
=
RequestMethod
.
PUT
)
public
void
rollback
(
@PathVariable
(
"releaseId"
)
long
releaseId
,
@RequestParam
(
"operator"
)
String
operator
)
{
...
...
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java
浏览文件 @
2a834828
...
...
@@ -21,6 +21,16 @@ import java.util.concurrent.TimeUnit;
@Component
public
class
BizConfig
extends
RefreshableConfig
{
private
static
final
int
DEFAULT_ITEM_KEY_LENGTH
=
128
;
private
static
final
int
DEFAULT_ITEM_VALUE_LENGTH
=
20000
;
private
static
final
int
DEFAULT_APPNAMESPACE_CACHE_REBUILD_INTERVAL
=
60
;
//60s
private
static
final
int
DEFAULT_GRAY_RELEASE_RULE_SCAN_INTERVAL
=
60
;
//60s
private
static
final
int
DEFAULT_APPNAMESPACE_CACHE_SCAN_INTERVAL
=
1
;
//1s
private
static
final
int
DEFAULT_RELEASE_MESSAGE_CACHE_SCAN_INTERVAL
=
1
;
//1s
private
static
final
int
DEFAULT_RELEASE_MESSAGE_SCAN_INTERVAL_IN_MS
=
1000
;
//1000ms
private
static
final
int
DEFAULT_RELEASE_MESSAGE_NOTIFICATION_BATCH
=
100
;
private
static
final
int
DEFAULT_RELEASE_MESSAGE_NOTIFICATION_BATCH_INTERVAL_IN_MILLI
=
100
;
//100ms
private
Gson
gson
=
new
Gson
();
private
static
final
Type
namespaceValueLengthOverrideTypeReference
=
new
TypeToken
<
Map
<
Long
,
Integer
>>()
{
...
...
@@ -44,18 +54,18 @@ public class BizConfig extends RefreshableConfig {
}
public
int
grayReleaseRuleScanInterval
()
{
int
interval
=
getIntProperty
(
"apollo.gray-release-rule-scan.interval"
,
60
);
return
checkInt
(
interval
,
1
,
Integer
.
MAX_VALUE
,
60
);
int
interval
=
getIntProperty
(
"apollo.gray-release-rule-scan.interval"
,
DEFAULT_GRAY_RELEASE_RULE_SCAN_INTERVAL
);
return
checkInt
(
interval
,
1
,
Integer
.
MAX_VALUE
,
DEFAULT_GRAY_RELEASE_RULE_SCAN_INTERVAL
);
}
public
int
itemKeyLengthLimit
()
{
int
limit
=
getIntProperty
(
"item.key.length.limit"
,
128
);
return
checkInt
(
limit
,
5
,
Integer
.
MAX_VALUE
,
128
);
int
limit
=
getIntProperty
(
"item.key.length.limit"
,
DEFAULT_ITEM_KEY_LENGTH
);
return
checkInt
(
limit
,
5
,
Integer
.
MAX_VALUE
,
DEFAULT_ITEM_KEY_LENGTH
);
}
public
int
itemValueLengthLimit
()
{
int
limit
=
getIntProperty
(
"item.value.length.limit"
,
20000
);
return
checkInt
(
limit
,
5
,
Integer
.
MAX_VALUE
,
20000
);
int
limit
=
getIntProperty
(
"item.value.length.limit"
,
DEFAULT_ITEM_VALUE_LENGTH
);
return
checkInt
(
limit
,
5
,
Integer
.
MAX_VALUE
,
DEFAULT_ITEM_VALUE_LENGTH
);
}
public
Map
<
Long
,
Integer
>
namespaceValueLengthLimitOverride
()
{
...
...
@@ -85,8 +95,8 @@ public class BizConfig extends RefreshableConfig {
}
public
int
appNamespaceCacheScanInterval
()
{
int
interval
=
getIntProperty
(
"apollo.app-namespace-cache-scan.interval"
,
1
);
return
checkInt
(
interval
,
1
,
Integer
.
MAX_VALUE
,
1
);
int
interval
=
getIntProperty
(
"apollo.app-namespace-cache-scan.interval"
,
DEFAULT_APPNAMESPACE_CACHE_SCAN_INTERVAL
);
return
checkInt
(
interval
,
1
,
Integer
.
MAX_VALUE
,
DEFAULT_APPNAMESPACE_CACHE_SCAN_INTERVAL
);
}
public
TimeUnit
appNamespaceCacheScanIntervalTimeUnit
()
{
...
...
@@ -94,8 +104,8 @@ public class BizConfig extends RefreshableConfig {
}
public
int
appNamespaceCacheRebuildInterval
()
{
int
interval
=
getIntProperty
(
"apollo.app-namespace-cache-rebuild.interval"
,
60
);
return
checkInt
(
interval
,
1
,
Integer
.
MAX_VALUE
,
60
);
int
interval
=
getIntProperty
(
"apollo.app-namespace-cache-rebuild.interval"
,
DEFAULT_APPNAMESPACE_CACHE_REBUILD_INTERVAL
);
return
checkInt
(
interval
,
1
,
Integer
.
MAX_VALUE
,
DEFAULT_APPNAMESPACE_CACHE_REBUILD_INTERVAL
);
}
public
TimeUnit
appNamespaceCacheRebuildIntervalTimeUnit
()
{
...
...
@@ -103,22 +113,31 @@ public class BizConfig extends RefreshableConfig {
}
public
int
releaseMessageCacheScanInterval
()
{
int
interval
=
getIntProperty
(
"apollo.release-message-cache-scan.interval"
,
1
);
return
checkInt
(
interval
,
1
,
Integer
.
MAX_VALUE
,
1
);
int
interval
=
getIntProperty
(
"apollo.release-message-cache-scan.interval"
,
DEFAULT_RELEASE_MESSAGE_CACHE_SCAN_INTERVAL
);
return
checkInt
(
interval
,
1
,
Integer
.
MAX_VALUE
,
DEFAULT_RELEASE_MESSAGE_CACHE_SCAN_INTERVAL
);
}
public
TimeUnit
releaseMessageCacheScanIntervalTimeUnit
()
{
return
TimeUnit
.
SECONDS
;
}
public
int
releaseMessageScanIntervalInMilli
()
{
int
interval
=
getIntProperty
(
"apollo.message-scan.interval"
,
DEFAULT_RELEASE_MESSAGE_SCAN_INTERVAL_IN_MS
);
return
checkInt
(
interval
,
100
,
Integer
.
MAX_VALUE
,
DEFAULT_RELEASE_MESSAGE_SCAN_INTERVAL_IN_MS
);
}
public
int
releaseMessageNotificationBatch
()
{
int
batch
=
getIntProperty
(
"apollo.release-message.notification.batch"
,
100
);
return
checkInt
(
batch
,
1
,
Integer
.
MAX_VALUE
,
100
);
int
batch
=
getIntProperty
(
"apollo.release-message.notification.batch"
,
DEFAULT_RELEASE_MESSAGE_NOTIFICATION_BATCH
);
return
checkInt
(
batch
,
1
,
Integer
.
MAX_VALUE
,
DEFAULT_RELEASE_MESSAGE_NOTIFICATION_BATCH
);
}
public
int
releaseMessageNotificationBatchIntervalInMilli
()
{
int
interval
=
getIntProperty
(
"apollo.release-message.notification.batch.interval"
,
100
);
return
checkInt
(
interval
,
1
,
Integer
.
MAX_VALUE
,
100
);
int
interval
=
getIntProperty
(
"apollo.release-message.notification.batch.interval"
,
DEFAULT_RELEASE_MESSAGE_NOTIFICATION_BATCH_INTERVAL_IN_MILLI
);
return
checkInt
(
interval
,
10
,
Integer
.
MAX_VALUE
,
DEFAULT_RELEASE_MESSAGE_NOTIFICATION_BATCH_INTERVAL_IN_MILLI
);
}
public
boolean
isConfigServiceCacheEnabled
()
{
return
getBooleanProperty
(
"config-service.cache.enabled"
,
false
);
}
int
checkInt
(
int
value
,
int
min
,
int
max
,
int
defaultValue
)
{
...
...
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/message/DatabaseMessageSender.java
浏览文件 @
2a834828
...
...
@@ -61,6 +61,7 @@ public class DatabaseMessageSender implements MessageSender {
}
catch
(
Throwable
ex
)
{
logger
.
error
(
"Sending message to database failed"
,
ex
);
transaction
.
setStatus
(
ex
);
throw
ex
;
}
finally
{
transaction
.
complete
();
}
...
...
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/message/ReleaseMessageScanner.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.biz.message
;
import
com.google.common.collect.Lists
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.framework.apollo.biz.repository.ReleaseMessageRepository
;
import
com.ctrip.framework.apollo.core.utils.ApolloThreadFactory
;
import
com.ctrip.framework.apollo.tracer.Tracer
;
import
com.ctrip.framework.apollo.tracer.spi.Transaction
;
import
java.util.List
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.ScheduledExecutorService
;
import
java.util.concurrent.TimeUnit
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.core.env.Environment
;
import
org.springframework.util.CollectionUtils
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.ScheduledExecutorService
;
import
java.util.concurrent.TimeUnit
;
import
com.ctrip.framework.apollo.biz.config.BizConfig
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.framework.apollo.biz.repository.ReleaseMessageRepository
;
import
com.ctrip.framework.apollo.core.utils.ApolloThreadFactory
;
import
com.ctrip.framework.apollo.tracer.Tracer
;
import
com.ctrip.framework.apollo.tracer.spi.Transaction
;
import
com.google.common.collect.Lists
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
ReleaseMessageScanner
implements
InitializingBean
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
ReleaseMessageScanner
.
class
);
private
static
final
int
DEFAULT_SCAN_INTERVAL_IN_MS
=
1000
;
@Autowired
private
Environment
env
;
private
BizConfig
bizConfig
;
@Autowired
private
ReleaseMessageRepository
releaseMessageRepository
;
private
int
databaseScanInterval
;
...
...
@@ -44,7 +41,7 @@ public class ReleaseMessageScanner implements InitializingBean {
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
populateDataBaseInterval
();
databaseScanInterval
=
bizConfig
.
releaseMessageScanIntervalInMilli
();
maxIdScanned
=
loadLargestMessageId
();
executorService
.
scheduleWithFixedDelay
((
Runnable
)
()
->
{
Transaction
transaction
=
Tracer
.
newTransaction
(
"Apollo.ReleaseMessageScanner"
,
"scanMessage"
);
...
...
@@ -57,7 +54,7 @@ public class ReleaseMessageScanner implements InitializingBean {
}
finally
{
transaction
.
complete
();
}
},
getDatabaseScanIntervalMs
(),
getDatabaseScanIntervalMs
()
,
TimeUnit
.
MILLISECONDS
);
},
databaseScanInterval
,
databaseScanInterval
,
TimeUnit
.
MILLISECONDS
);
}
...
...
@@ -124,21 +121,4 @@ public class ReleaseMessageScanner implements InitializingBean {
}
}
}
private
void
populateDataBaseInterval
()
{
databaseScanInterval
=
DEFAULT_SCAN_INTERVAL_IN_MS
;
try
{
String
interval
=
env
.
getProperty
(
"apollo.message-scan.interval"
);
if
(!
Objects
.
isNull
(
interval
))
{
databaseScanInterval
=
Integer
.
parseInt
(
interval
);
}
}
catch
(
Throwable
ex
)
{
Tracer
.
logError
(
ex
);
logger
.
error
(
"Load apollo message scan interval from system property failed"
,
ex
);
}
}
private
int
getDatabaseScanIntervalMs
()
{
return
databaseScanInterval
;
}
}
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/NamespaceService.java
浏览文件 @
2a834828
...
...
@@ -8,7 +8,10 @@ import com.ctrip.framework.apollo.biz.entity.Cluster;
import
com.ctrip.framework.apollo.biz.entity.Item
;
import
com.ctrip.framework.apollo.biz.entity.Namespace
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.message.MessageSender
;
import
com.ctrip.framework.apollo.biz.message.Topics
;
import
com.ctrip.framework.apollo.biz.repository.NamespaceRepository
;
import
com.ctrip.framework.apollo.biz.utils.ReleaseMessageKeyGenerator
;
import
com.ctrip.framework.apollo.common.constants.GsonType
;
import
com.ctrip.framework.apollo.common.constants.NamespaceBranchStatus
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
...
...
@@ -59,6 +62,8 @@ public class NamespaceService {
private
NamespaceLockService
namespaceLockService
;
@Autowired
private
InstanceService
instanceService
;
@Autowired
private
MessageSender
messageSender
;
public
Namespace
findOne
(
Long
namespaceId
)
{
...
...
@@ -282,7 +287,13 @@ public class NamespaceService {
auditService
.
audit
(
Namespace
.
class
.
getSimpleName
(),
namespace
.
getId
(),
Audit
.
OP
.
DELETE
,
operator
);
return
namespaceRepository
.
save
(
namespace
);
Namespace
deleted
=
namespaceRepository
.
save
(
namespace
);
//Publish release message to do some clean up in config service, such as updating the cache
messageSender
.
sendMessage
(
ReleaseMessageKeyGenerator
.
generate
(
appId
,
clusterName
,
namespaceName
),
Topics
.
APOLLO_RELEASE_TOPIC
);
return
deleted
;
}
@Transactional
...
...
apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/message/DatabaseMessageSenderTest.java
浏览文件 @
2a834828
...
...
@@ -12,9 +12,11 @@ import org.springframework.test.util.ReflectionTestUtils;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
mockito
.
Mockito
.
any
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
never
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
* @author Jason Song(song_s@ctrip.com)
...
...
@@ -33,6 +35,11 @@ public class DatabaseMessageSenderTest extends AbstractUnitTest{
@Test
public
void
testSendMessage
()
throws
Exception
{
String
someMessage
=
"some-message"
;
long
someId
=
1
;
ReleaseMessage
someReleaseMessage
=
mock
(
ReleaseMessage
.
class
);
when
(
someReleaseMessage
.
getId
()).
thenReturn
(
someId
);
when
(
releaseMessageRepository
.
save
(
any
(
ReleaseMessage
.
class
))).
thenReturn
(
someReleaseMessage
);
ArgumentCaptor
<
ReleaseMessage
>
captor
=
ArgumentCaptor
.
forClass
(
ReleaseMessage
.
class
);
messageSender
.
sendMessage
(
someMessage
,
Topics
.
APOLLO_RELEASE_TOPIC
);
...
...
@@ -50,4 +57,12 @@ public class DatabaseMessageSenderTest extends AbstractUnitTest{
verify
(
releaseMessageRepository
,
never
()).
save
(
any
(
ReleaseMessage
.
class
));
}
@Test
(
expected
=
RuntimeException
.
class
)
public
void
testSendMessageFailed
()
throws
Exception
{
String
someMessage
=
"some-message"
;
when
(
releaseMessageRepository
.
save
(
any
(
ReleaseMessage
.
class
))).
thenThrow
(
new
RuntimeException
());
messageSender
.
sendMessage
(
someMessage
,
Topics
.
APOLLO_RELEASE_TOPIC
);
}
}
apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/message/ReleaseMessageScannerTest.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.biz.message
;
import
com.ctrip.framework.apollo.biz.config.BizConfig
;
import
com.google.common.collect.Lists
;
import
com.google.common.util.concurrent.SettableFuture
;
...
...
@@ -26,7 +27,7 @@ public class ReleaseMessageScannerTest extends AbstractUnitTest {
@Mock
private
ReleaseMessageRepository
releaseMessageRepository
;
@Mock
private
Environment
env
;
private
BizConfig
bizConfig
;
private
int
databaseScanInterval
;
@Before
...
...
@@ -34,9 +35,9 @@ public class ReleaseMessageScannerTest extends AbstractUnitTest {
releaseMessageScanner
=
new
ReleaseMessageScanner
();
ReflectionTestUtils
.
setField
(
releaseMessageScanner
,
"releaseMessageRepository"
,
releaseMessageRepository
);
ReflectionTestUtils
.
setField
(
releaseMessageScanner
,
"
env"
,
env
);
ReflectionTestUtils
.
setField
(
releaseMessageScanner
,
"
bizConfig"
,
bizConfig
);
databaseScanInterval
=
100
;
//100 ms
when
(
env
.
getProperty
(
"apollo.message-scan.interval"
)).
thenReturn
(
String
.
valueOf
(
databaseScanInterval
)
);
when
(
bizConfig
.
releaseMessageScanIntervalInMilli
()).
thenReturn
(
databaseScanInterval
);
releaseMessageScanner
.
afterPropertiesSet
();
}
...
...
apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigLongPollService.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.internals
;
import
java.lang.reflect.Type
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Random
;
import
java.util.concurrent.ConcurrentMap
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Strings
;
import
com.google.common.collect.HashMultimap
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Maps
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Multimaps
;
import
com.google.common.escape.Escaper
;
import
com.google.common.net.UrlEscapers
;
import
com.google.common.reflect.TypeToken
;
import
com.google.common.util.concurrent.RateLimiter
;
import
com.google.gson.Gson
;
import
com.ctrip.framework.apollo.build.ApolloInjector
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfigNotification
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.ctrip.framework.apollo.core.dto.ServiceDTO
;
import
com.ctrip.framework.apollo.core.enums.ConfigFileFormat
;
import
com.ctrip.framework.apollo.core.schedule.ExponentialSchedulePolicy
;
...
...
@@ -29,18 +31,19 @@ import com.ctrip.framework.apollo.util.ExceptionUtil;
import
com.ctrip.framework.apollo.util.http.HttpRequest
;
import
com.ctrip.framework.apollo.util.http.HttpResponse
;
import
com.ctrip.framework.apollo.util.http.HttpUtil
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Strings
;
import
com.google.common.collect.HashMultimap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Maps
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Multimaps
;
import
com.google.common.escape.Escaper
;
import
com.google.common.net.UrlEscapers
;
import
com.google.common.reflect.TypeToken
;
import
com.google.common.util.concurrent.RateLimiter
;
import
com.google.gson.Gson
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.lang.reflect.Type
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Random
;
import
java.util.concurrent.ConcurrentMap
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicBoolean
;
/**
* @author Jason Song(song_s@ctrip.com)
...
...
@@ -50,7 +53,7 @@ public class RemoteConfigLongPollService {
private
static
final
Joiner
STRING_JOINER
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
);
private
static
final
Joiner
.
MapJoiner
MAP_JOINER
=
Joiner
.
on
(
"&"
).
withKeyValueSeparator
(
"="
);
private
static
final
Escaper
queryParamEscaper
=
UrlEscapers
.
urlFormParameterEscaper
();
private
static
final
long
INIT_NOTIFICATION_ID
=
-
1
;
private
static
final
long
INIT_NOTIFICATION_ID
=
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
;
private
final
ExecutorService
m_longPollingService
;
private
final
AtomicBoolean
m_longPollingStopped
;
private
SchedulePolicy
m_longPollFailSchedulePolicyInSecond
;
...
...
@@ -58,6 +61,7 @@ public class RemoteConfigLongPollService {
private
final
AtomicBoolean
m_longPollStarted
;
private
final
Multimap
<
String
,
RemoteConfigRepository
>
m_longPollNamespaces
;
private
final
ConcurrentMap
<
String
,
Long
>
m_notifications
;
private
final
Map
<
String
,
ApolloNotificationMessages
>
m_remoteNotificationMessages
;
//namespaceName -> watchedKey -> notificationId
private
Type
m_responseType
;
private
Gson
gson
;
private
ConfigUtil
m_configUtil
;
...
...
@@ -76,6 +80,7 @@ public class RemoteConfigLongPollService {
m_longPollNamespaces
=
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.<
String
,
RemoteConfigRepository
>
create
());
m_notifications
=
Maps
.
newConcurrentMap
();
m_remoteNotificationMessages
=
Maps
.
newConcurrentMap
();
m_responseType
=
new
TypeToken
<
List
<
ApolloConfigNotification
>>()
{
}.
getType
();
gson
=
new
Gson
();
...
...
@@ -143,13 +148,14 @@ public class RemoteConfigLongPollService {
}
}
Transaction
transaction
=
Tracer
.
newTransaction
(
"Apollo.ConfigService"
,
"pollNotification"
);
String
url
=
null
;
try
{
if
(
lastServiceDto
==
null
)
{
List
<
ServiceDTO
>
configServices
=
getConfigServices
();
lastServiceDto
=
configServices
.
get
(
random
.
nextInt
(
configServices
.
size
()));
}
String
url
=
url
=
assembleLongPollRefreshUrl
(
lastServiceDto
.
getHomepageUrl
(),
appId
,
cluster
,
dataCenter
,
m_notifications
);
...
...
@@ -166,6 +172,7 @@ public class RemoteConfigLongPollService {
logger
.
debug
(
"Long polling response: {}, url: {}"
,
response
.
getStatusCode
(),
url
);
if
(
response
.
getStatusCode
()
==
200
&&
response
.
getBody
()
!=
null
)
{
updateNotifications
(
response
.
getBody
());
updateRemoteNotifications
(
response
.
getBody
());
transaction
.
addData
(
"Result"
,
response
.
getBody
().
toString
());
notify
(
lastServiceDto
,
response
.
getBody
());
}
...
...
@@ -184,9 +191,8 @@ public class RemoteConfigLongPollService {
transaction
.
setStatus
(
ex
);
long
sleepTimeInSecond
=
m_longPollFailSchedulePolicyInSecond
.
fail
();
logger
.
warn
(
"Long polling failed, will retry in {} seconds. appId: {}, cluster: {}, namespaces: {}, reason: {}"
,
sleepTimeInSecond
,
appId
,
cluster
,
assembleNamespaces
(),
ExceptionUtil
.
getDetailMessage
(
ex
));
"Long polling failed, will retry in {} seconds. appId: {}, cluster: {}, namespaces: {}, long polling url: {}, reason: {}"
,
sleepTimeInSecond
,
appId
,
cluster
,
assembleNamespaces
(),
url
,
ExceptionUtil
.
getDetailMessage
(
ex
));
try
{
TimeUnit
.
SECONDS
.
sleep
(
sleepTimeInSecond
);
}
catch
(
InterruptedException
ie
)
{
...
...
@@ -207,12 +213,14 @@ public class RemoteConfigLongPollService {
//create a new list to avoid ConcurrentModificationException
List
<
RemoteConfigRepository
>
toBeNotified
=
Lists
.
newArrayList
(
m_longPollNamespaces
.
get
(
namespaceName
));
ApolloNotificationMessages
originalMessages
=
m_remoteNotificationMessages
.
get
(
namespaceName
);
ApolloNotificationMessages
remoteMessages
=
originalMessages
==
null
?
null
:
originalMessages
.
clone
();
//since .properties are filtered out by default, so we need to check if there is any listener for it
toBeNotified
.
addAll
(
m_longPollNamespaces
.
get
(
String
.
format
(
"%s.%s"
,
namespaceName
,
ConfigFileFormat
.
Properties
.
getValue
())));
for
(
RemoteConfigRepository
remoteConfigRepository
:
toBeNotified
)
{
try
{
remoteConfigRepository
.
onLongPollNotified
(
lastServiceDto
);
remoteConfigRepository
.
onLongPollNotified
(
lastServiceDto
,
remoteMessages
);
}
catch
(
Throwable
ex
)
{
Tracer
.
logError
(
ex
);
}
...
...
@@ -238,6 +246,27 @@ public class RemoteConfigLongPollService {
}
}
private
void
updateRemoteNotifications
(
List
<
ApolloConfigNotification
>
deltaNotifications
)
{
for
(
ApolloConfigNotification
notification
:
deltaNotifications
)
{
if
(
Strings
.
isNullOrEmpty
(
notification
.
getNamespaceName
()))
{
continue
;
}
if
(
notification
.
getMessages
()
==
null
||
notification
.
getMessages
().
isEmpty
())
{
continue
;
}
ApolloNotificationMessages
localRemoteMessages
=
m_remoteNotificationMessages
.
get
(
notification
.
getNamespaceName
());
if
(
localRemoteMessages
==
null
)
{
localRemoteMessages
=
new
ApolloNotificationMessages
();
m_remoteNotificationMessages
.
put
(
notification
.
getNamespaceName
(),
localRemoteMessages
);
}
localRemoteMessages
.
mergeFrom
(
notification
.
getMessages
());
}
}
private
String
assembleNamespaces
()
{
return
STRING_JOINER
.
join
(
m_longPollNamespaces
.
keySet
());
}
...
...
@@ -269,9 +298,7 @@ public class RemoteConfigLongPollService {
String
assembleNotifications
(
Map
<
String
,
Long
>
notificationsMap
)
{
List
<
ApolloConfigNotification
>
notifications
=
Lists
.
newArrayList
();
for
(
Map
.
Entry
<
String
,
Long
>
entry
:
notificationsMap
.
entrySet
())
{
ApolloConfigNotification
notification
=
new
ApolloConfigNotification
();
notification
.
setNamespaceName
(
entry
.
getKey
());
notification
.
setNotificationId
(
entry
.
getValue
());
ApolloConfigNotification
notification
=
new
ApolloConfigNotification
(
entry
.
getKey
(),
entry
.
getValue
());
notifications
.
add
(
notification
);
}
return
gson
.
toJson
(
notifications
);
...
...
apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java
浏览文件 @
2a834828
...
...
@@ -17,6 +17,7 @@ import com.ctrip.framework.apollo.Apollo;
import
com.ctrip.framework.apollo.build.ApolloInjector
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfig
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.ctrip.framework.apollo.core.dto.ServiceDTO
;
import
com.ctrip.framework.apollo.core.schedule.ExponentialSchedulePolicy
;
import
com.ctrip.framework.apollo.core.schedule.SchedulePolicy
;
...
...
@@ -37,6 +38,7 @@ import com.google.common.collect.Maps;
import
com.google.common.escape.Escaper
;
import
com.google.common.net.UrlEscapers
;
import
com.google.common.util.concurrent.RateLimiter
;
import
com.google.gson.Gson
;
/**
* @author Jason Song(song_s@ctrip.com)
...
...
@@ -53,9 +55,11 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
private
final
String
m_namespace
;
private
final
static
ScheduledExecutorService
m_executorService
;
private
AtomicReference
<
ServiceDTO
>
m_longPollServiceDto
;
private
AtomicReference
<
ApolloNotificationMessages
>
m_remoteMessages
;
private
RateLimiter
m_loadConfigRateLimiter
;
private
AtomicBoolean
m_configNeedForceRefresh
;
private
SchedulePolicy
m_loadConfigFailSchedulePolicy
;
private
Gson
gson
;
private
static
final
Escaper
pathEscaper
=
UrlEscapers
.
urlPathSegmentEscaper
();
private
static
final
Escaper
queryParamEscaper
=
UrlEscapers
.
urlFormParameterEscaper
();
...
...
@@ -77,10 +81,12 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
m_serviceLocator
=
ApolloInjector
.
getInstance
(
ConfigServiceLocator
.
class
);
remoteConfigLongPollService
=
ApolloInjector
.
getInstance
(
RemoteConfigLongPollService
.
class
);
m_longPollServiceDto
=
new
AtomicReference
<>();
m_remoteMessages
=
new
AtomicReference
<>();
m_loadConfigRateLimiter
=
RateLimiter
.
create
(
m_configUtil
.
getLoadConfigQPS
());
m_configNeedForceRefresh
=
new
AtomicBoolean
(
true
);
m_loadConfigFailSchedulePolicy
=
new
ExponentialSchedulePolicy
(
m_configUtil
.
getOnErrorRetryInterval
(),
m_configUtil
.
getOnErrorRetryInterval
()
*
8
);
gson
=
new
Gson
();
this
.
trySync
();
this
.
schedulePeriodicRefresh
();
this
.
scheduleLongPollingRefresh
();
...
...
@@ -167,6 +173,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
Throwable
exception
=
null
;
List
<
ServiceDTO
>
configServices
=
getConfigServices
();
String
url
=
null
;
for
(
int
i
=
0
;
i
<
maxRetries
;
i
++)
{
List
<
ServiceDTO
>
randomConfigServices
=
Lists
.
newLinkedList
(
configServices
);
Collections
.
shuffle
(
randomConfigServices
);
...
...
@@ -188,9 +195,8 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
}
}
String
url
=
assembleQueryConfigUrl
(
configService
.
getHomepageUrl
(),
appId
,
cluster
,
m_namespace
,
dataCenter
,
m_configCache
.
get
());
url
=
assembleQueryConfigUrl
(
configService
.
getHomepageUrl
(),
appId
,
cluster
,
m_namespace
,
dataCenter
,
m_remoteMessages
.
get
(),
m_configCache
.
get
());
logger
.
debug
(
"Loading config from {}"
,
url
);
HttpRequest
request
=
new
HttpRequest
(
url
);
...
...
@@ -245,13 +251,13 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
}
String
message
=
String
.
format
(
"Load Apollo Config failed - appId: %s, cluster: %s, namespace: %s"
,
appId
,
cluster
,
m_namespace
);
"Load Apollo Config failed - appId: %s, cluster: %s, namespace: %s
, url: %s
"
,
appId
,
cluster
,
m_namespace
,
url
);
throw
new
ApolloConfigException
(
message
,
exception
);
}
String
assembleQueryConfigUrl
(
String
uri
,
String
appId
,
String
cluster
,
String
namespace
,
String
dataCenter
,
ApolloConfig
previousConfig
)
{
String
dataCenter
,
Apollo
NotificationMessages
remoteMessages
,
Apollo
Config
previousConfig
)
{
String
path
=
"configs/%s/%s/%s"
;
List
<
String
>
pathParams
=
...
...
@@ -272,6 +278,10 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
queryParams
.
put
(
"ip"
,
queryParamEscaper
.
escape
(
localIp
));
}
if
(
remoteMessages
!=
null
)
{
queryParams
.
put
(
"messages"
,
queryParamEscaper
.
escape
(
gson
.
toJson
(
remoteMessages
)));
}
String
pathExpanded
=
String
.
format
(
path
,
pathParams
.
toArray
());
if
(!
queryParams
.
isEmpty
())
{
...
...
@@ -287,8 +297,9 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
remoteConfigLongPollService
.
submit
(
m_namespace
,
this
);
}
public
void
onLongPollNotified
(
ServiceDTO
longPollNotifiedServiceDto
)
{
public
void
onLongPollNotified
(
ServiceDTO
longPollNotifiedServiceDto
,
ApolloNotificationMessages
remoteMessages
)
{
m_longPollServiceDto
.
set
(
longPollNotifiedServiceDto
);
m_remoteMessages
.
set
(
remoteMessages
);
m_executorService
.
submit
(
new
Runnable
()
{
@Override
public
void
run
()
{
...
...
apollo-client/src/test/java/com/ctrip/framework/apollo/internals/RemoteConfigLongPollServiceTest.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.internals
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
mockito
.
Matchers
.
any
;
import
static
org
.
mockito
.
Matchers
.
anyLong
;
import
static
org
.
mockito
.
Matchers
.
eq
;
import
static
org
.
mockito
.
Mockito
.
doAnswer
;
import
static
org
.
mockito
.
Mockito
.
mock
;
...
...
@@ -10,9 +12,11 @@ import static org.mockito.Mockito.times;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
import
com.ctrip.framework.apollo.Apollo
;
import
java.lang.reflect.Type
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Properties
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicInteger
;
...
...
@@ -21,6 +25,7 @@ import javax.servlet.http.HttpServletResponse;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.ArgumentCaptor
;
import
org.mockito.Mock
;
import
org.mockito.invocation.InvocationOnMock
;
import
org.mockito.runners.MockitoJUnitRunner
;
...
...
@@ -29,6 +34,7 @@ import org.springframework.test.util.ReflectionTestUtils;
import
com.ctrip.framework.apollo.build.MockInjector
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfigNotification
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.ctrip.framework.apollo.core.dto.ServiceDTO
;
import
com.ctrip.framework.apollo.util.ConfigUtil
;
import
com.ctrip.framework.apollo.util.http.HttpRequest
;
...
...
@@ -114,7 +120,7 @@ public class RemoteConfigLongPollServiceTest {
remoteConfigLongPollService
.
stopLongPollingRefresh
();
verify
(
someRepository
,
never
()).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
verify
(
someRepository
,
never
()).
onLongPollNotified
(
any
(
ServiceDTO
.
class
)
,
any
(
ApolloNotificationMessages
.
class
)
);
}
@Test
...
...
@@ -122,8 +128,17 @@ public class RemoteConfigLongPollServiceTest {
RemoteConfigRepository
someRepository
=
mock
(
RemoteConfigRepository
.
class
);
final
String
someNamespace
=
"someNamespace"
;
ApolloNotificationMessages
notificationMessages
=
new
ApolloNotificationMessages
();
String
someKey
=
"someKey"
;
long
someNotificationId
=
1
;
String
anotherKey
=
"anotherKey"
;
long
anotherNotificationId
=
2
;
notificationMessages
.
put
(
someKey
,
someNotificationId
);
notificationMessages
.
put
(
anotherKey
,
anotherNotificationId
);
ApolloConfigNotification
someNotification
=
mock
(
ApolloConfigNotification
.
class
);
when
(
someNotification
.
getNamespaceName
()).
thenReturn
(
someNamespace
);
when
(
someNotification
.
getMessages
()).
thenReturn
(
notificationMessages
);
when
(
pollResponse
.
getStatusCode
()).
thenReturn
(
HttpServletResponse
.
SC_OK
);
when
(
pollResponse
.
getBody
()).
thenReturn
(
Lists
.
newArrayList
(
someNotification
));
...
...
@@ -148,7 +163,7 @@ public class RemoteConfigLongPollServiceTest {
onNotified
.
set
(
true
);
return
null
;
}
}).
when
(
someRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
}).
when
(
someRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
)
,
any
(
ApolloNotificationMessages
.
class
)
);
remoteConfigLongPollService
.
submit
(
someNamespace
,
someRepository
);
...
...
@@ -156,7 +171,14 @@ public class RemoteConfigLongPollServiceTest {
remoteConfigLongPollService
.
stopLongPollingRefresh
();
verify
(
someRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
final
ArgumentCaptor
<
ApolloNotificationMessages
>
captor
=
ArgumentCaptor
.
forClass
(
ApolloNotificationMessages
.
class
);
verify
(
someRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
),
captor
.
capture
());
ApolloNotificationMessages
captured
=
captor
.
getValue
();
assertEquals
(
2
,
captured
.
getDetails
().
size
());
assertEquals
(
someNotificationId
,
captured
.
get
(
someKey
).
longValue
());
assertEquals
(
anotherNotificationId
,
captured
.
get
(
anotherKey
).
longValue
());
}
@Test
...
...
@@ -221,7 +243,7 @@ public class RemoteConfigLongPollServiceTest {
onAnotherRepositoryNotified
.
set
(
true
);
return
null
;
}
}).
when
(
anotherRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
}).
when
(
anotherRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
)
,
any
(
ApolloNotificationMessages
.
class
)
);
remoteConfigLongPollService
.
submit
(
someNamespace
,
someRepository
);
...
...
@@ -233,8 +255,8 @@ public class RemoteConfigLongPollServiceTest {
remoteConfigLongPollService
.
stopLongPollingRefresh
();
verify
(
someRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
verify
(
anotherRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
verify
(
someRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
)
,
any
(
ApolloNotificationMessages
.
class
)
);
verify
(
anotherRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
)
,
any
(
ApolloNotificationMessages
.
class
)
);
}
@Test
...
...
@@ -244,11 +266,22 @@ public class RemoteConfigLongPollServiceTest {
final
String
someNamespace
=
"someNamespace"
;
final
String
anotherNamespace
=
"anotherNamespace"
;
ApolloNotificationMessages
notificationMessages
=
new
ApolloNotificationMessages
();
String
someKey
=
"someKey"
;
long
someNotificationId
=
1
;
notificationMessages
.
put
(
someKey
,
someNotificationId
);
ApolloNotificationMessages
anotherNotificationMessages
=
new
ApolloNotificationMessages
();
String
anotherKey
=
"anotherKey"
;
long
anotherNotificationId
=
2
;
anotherNotificationMessages
.
put
(
anotherKey
,
anotherNotificationId
);
final
ApolloConfigNotification
someNotification
=
mock
(
ApolloConfigNotification
.
class
);
when
(
someNotification
.
getNamespaceName
()).
thenReturn
(
someNamespace
);
when
(
someNotification
.
getMessages
()).
thenReturn
(
notificationMessages
);
final
ApolloConfigNotification
anotherNotification
=
mock
(
ApolloConfigNotification
.
class
);
when
(
anotherNotification
.
getNamespaceName
()).
thenReturn
(
anotherNamespace
);
when
(
anotherNotification
.
getMessages
()).
thenReturn
(
anotherNotificationMessages
);
when
(
pollResponse
.
getStatusCode
()).
thenReturn
(
HttpServletResponse
.
SC_OK
);
when
(
pollResponse
.
getBody
()).
thenReturn
(
Lists
.
newArrayList
(
someNotification
,
anotherNotification
));
...
...
@@ -273,7 +306,7 @@ public class RemoteConfigLongPollServiceTest {
someRepositoryNotified
.
set
(
true
);
return
null
;
}
}).
when
(
someRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
}).
when
(
someRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
)
,
any
(
ApolloNotificationMessages
.
class
)
);
final
SettableFuture
<
Boolean
>
anotherRepositoryNotified
=
SettableFuture
.
create
();
doAnswer
(
new
Answer
<
Void
>()
{
@Override
...
...
@@ -281,7 +314,7 @@ public class RemoteConfigLongPollServiceTest {
anotherRepositoryNotified
.
set
(
true
);
return
null
;
}
}).
when
(
anotherRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
}).
when
(
anotherRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
)
,
any
(
ApolloNotificationMessages
.
class
)
);
remoteConfigLongPollService
.
submit
(
someNamespace
,
someRepository
);
remoteConfigLongPollService
.
submit
(
anotherNamespace
,
anotherRepository
);
...
...
@@ -291,8 +324,101 @@ public class RemoteConfigLongPollServiceTest {
remoteConfigLongPollService
.
stopLongPollingRefresh
();
verify
(
someRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
verify
(
anotherRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
));
final
ArgumentCaptor
<
ApolloNotificationMessages
>
captor
=
ArgumentCaptor
.
forClass
(
ApolloNotificationMessages
.
class
);
final
ArgumentCaptor
<
ApolloNotificationMessages
>
anotherCaptor
=
ArgumentCaptor
.
forClass
(
ApolloNotificationMessages
.
class
);
verify
(
someRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
),
captor
.
capture
());
verify
(
anotherRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
),
anotherCaptor
.
capture
());
ApolloNotificationMessages
result
=
captor
.
getValue
();
assertEquals
(
1
,
result
.
getDetails
().
size
());
assertEquals
(
someNotificationId
,
result
.
get
(
someKey
).
longValue
());
ApolloNotificationMessages
anotherResult
=
anotherCaptor
.
getValue
();
assertEquals
(
1
,
anotherResult
.
getDetails
().
size
());
assertEquals
(
anotherNotificationId
,
anotherResult
.
get
(
anotherKey
).
longValue
());
}
@Test
public
void
testSubmitLongPollNamespaceWithMessagesUpdated
()
throws
Exception
{
RemoteConfigRepository
someRepository
=
mock
(
RemoteConfigRepository
.
class
);
final
String
someNamespace
=
"someNamespace"
;
ApolloNotificationMessages
notificationMessages
=
new
ApolloNotificationMessages
();
String
someKey
=
"someKey"
;
long
someNotificationId
=
1
;
notificationMessages
.
put
(
someKey
,
someNotificationId
);
ApolloConfigNotification
someNotification
=
mock
(
ApolloConfigNotification
.
class
);
when
(
someNotification
.
getNamespaceName
()).
thenReturn
(
someNamespace
);
when
(
someNotification
.
getMessages
()).
thenReturn
(
notificationMessages
);
when
(
pollResponse
.
getStatusCode
()).
thenReturn
(
HttpServletResponse
.
SC_OK
);
when
(
pollResponse
.
getBody
()).
thenReturn
(
Lists
.
newArrayList
(
someNotification
));
doAnswer
(
new
Answer
<
HttpResponse
<
List
<
ApolloConfigNotification
>>>()
{
@Override
public
HttpResponse
<
List
<
ApolloConfigNotification
>>
answer
(
InvocationOnMock
invocation
)
throws
Throwable
{
try
{
TimeUnit
.
MILLISECONDS
.
sleep
(
50
);
}
catch
(
InterruptedException
e
)
{
}
return
pollResponse
;
}
}).
when
(
httpUtil
).
doGet
(
any
(
HttpRequest
.
class
),
eq
(
responseType
));
final
SettableFuture
<
Boolean
>
onNotified
=
SettableFuture
.
create
();
doAnswer
(
new
Answer
<
Void
>()
{
@Override
public
Void
answer
(
InvocationOnMock
invocation
)
throws
Throwable
{
onNotified
.
set
(
true
);
return
null
;
}
}).
when
(
someRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
),
any
(
ApolloNotificationMessages
.
class
));
remoteConfigLongPollService
.
submit
(
someNamespace
,
someRepository
);
onNotified
.
get
(
5000
,
TimeUnit
.
MILLISECONDS
);
//reset to 304
when
(
pollResponse
.
getStatusCode
()).
thenReturn
(
HttpServletResponse
.
SC_NOT_MODIFIED
);
final
ArgumentCaptor
<
ApolloNotificationMessages
>
captor
=
ArgumentCaptor
.
forClass
(
ApolloNotificationMessages
.
class
);
verify
(
someRepository
,
times
(
1
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
),
captor
.
capture
());
ApolloNotificationMessages
captured
=
captor
.
getValue
();
assertEquals
(
1
,
captured
.
getDetails
().
size
());
assertEquals
(
someNotificationId
,
captured
.
get
(
someKey
).
longValue
());
final
SettableFuture
<
Boolean
>
anotherOnNotified
=
SettableFuture
.
create
();
doAnswer
(
new
Answer
<
Void
>()
{
@Override
public
Void
answer
(
InvocationOnMock
invocation
)
throws
Throwable
{
anotherOnNotified
.
set
(
true
);
return
null
;
}
}).
when
(
someRepository
).
onLongPollNotified
(
any
(
ServiceDTO
.
class
),
any
(
ApolloNotificationMessages
.
class
));
String
anotherKey
=
"anotherKey"
;
long
anotherNotificationId
=
2
;
notificationMessages
.
put
(
anotherKey
,
anotherNotificationId
);
//send notifications
when
(
pollResponse
.
getStatusCode
()).
thenReturn
(
HttpServletResponse
.
SC_OK
);
anotherOnNotified
.
get
(
5000
,
TimeUnit
.
MILLISECONDS
);
remoteConfigLongPollService
.
stopLongPollingRefresh
();
verify
(
someRepository
,
times
(
2
)).
onLongPollNotified
(
any
(
ServiceDTO
.
class
),
captor
.
capture
());
captured
=
captor
.
getValue
();
assertEquals
(
2
,
captured
.
getDetails
().
size
());
assertEquals
(
someNotificationId
,
captured
.
get
(
someKey
).
longValue
());
assertEquals
(
anotherNotificationId
,
captured
.
get
(
anotherKey
).
longValue
());
}
@Test
...
...
apollo-client/src/test/java/com/ctrip/framework/apollo/internals/RemoteConfigRepositoryTest.java
浏览文件 @
2a834828
...
...
@@ -4,8 +4,10 @@ import static org.junit.Assert.assertEquals;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
mockito
.
Matchers
.
eq
;
import
static
org
.
mockito
.
Mockito
.
any
;
import
static
org
.
mockito
.
Mockito
.
atLeast
;
import
static
org
.
mockito
.
Mockito
.
doAnswer
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
spy
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
...
...
@@ -30,6 +32,7 @@ import org.mockito.stubbing.Answer;
import
com.ctrip.framework.apollo.build.MockInjector
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfig
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfigNotification
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.ctrip.framework.apollo.core.dto.ServiceDTO
;
import
com.ctrip.framework.apollo.exceptions.ApolloConfigException
;
import
com.ctrip.framework.apollo.util.ConfigUtil
;
...
...
@@ -39,7 +42,9 @@ import com.ctrip.framework.apollo.util.http.HttpUtil;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Maps
;
import
com.google.common.net.UrlEscapers
;
import
com.google.common.util.concurrent.SettableFuture
;
import
com.google.gson.Gson
;
/**
* Created by Jason on 4/9/16.
...
...
@@ -49,6 +54,9 @@ public class RemoteConfigRepositoryTest {
@Mock
private
ConfigServiceLocator
configServiceLocator
;
private
String
someNamespace
;
private
String
someServerUrl
;
private
ConfigUtil
configUtil
;
private
HttpUtil
httpUtil
;
@Mock
private
static
HttpResponse
<
ApolloConfig
>
someResponse
;
@Mock
...
...
@@ -62,9 +70,10 @@ public class RemoteConfigRepositoryTest {
when
(
pollResponse
.
getStatusCode
()).
thenReturn
(
HttpServletResponse
.
SC_NOT_MODIFIED
);
MockInjector
.
reset
();
MockInjector
.
setInstance
(
ConfigUtil
.
class
,
new
MockConfigUtil
());
configUtil
=
new
MockConfigUtil
();
MockInjector
.
setInstance
(
ConfigUtil
.
class
,
configUtil
);
String
someServerUrl
=
"http://someServer"
;
someServerUrl
=
"http://someServer"
;
ServiceDTO
serviceDTO
=
mock
(
ServiceDTO
.
class
);
...
...
@@ -72,7 +81,8 @@ public class RemoteConfigRepositoryTest {
when
(
configServiceLocator
.
getConfigServices
()).
thenReturn
(
Lists
.
newArrayList
(
serviceDTO
));
MockInjector
.
setInstance
(
ConfigServiceLocator
.
class
,
configServiceLocator
);
MockInjector
.
setInstance
(
HttpUtil
.
class
,
new
MockHttpUtil
());
httpUtil
=
spy
(
new
MockHttpUtil
());
MockInjector
.
setInstance
(
HttpUtil
.
class
,
httpUtil
);
remoteConfigLongPollService
=
new
RemoteConfigLongPollService
();
...
...
@@ -164,8 +174,15 @@ public class RemoteConfigRepositoryTest {
Map
<
String
,
String
>
newConfigurations
=
ImmutableMap
.
of
(
"someKey"
,
"anotherValue"
);
ApolloConfig
newApolloConfig
=
assembleApolloConfig
(
newConfigurations
);
ApolloNotificationMessages
notificationMessages
=
new
ApolloNotificationMessages
();
String
someKey
=
"someKey"
;
long
someNotificationId
=
1
;
notificationMessages
.
put
(
someKey
,
someNotificationId
);
ApolloConfigNotification
someNotification
=
mock
(
ApolloConfigNotification
.
class
);
when
(
someNotification
.
getNamespaceName
()).
thenReturn
(
someNamespace
);
when
(
someNotification
.
getMessages
()).
thenReturn
(
notificationMessages
);
when
(
pollResponse
.
getStatusCode
()).
thenReturn
(
HttpServletResponse
.
SC_OK
);
when
(
pollResponse
.
getBody
()).
thenReturn
(
Lists
.
newArrayList
(
someNotification
));
...
...
@@ -177,21 +194,37 @@ public class RemoteConfigRepositoryTest {
verify
(
someListener
,
times
(
1
)).
onRepositoryChange
(
eq
(
someNamespace
),
captor
.
capture
());
assertEquals
(
newConfigurations
,
captor
.
getValue
());
final
ArgumentCaptor
<
HttpRequest
>
httpRequestArgumentCaptor
=
ArgumentCaptor
.
forClass
(
HttpRequest
.
class
);
verify
(
httpUtil
,
atLeast
(
2
)).
doGet
(
httpRequestArgumentCaptor
.
capture
(),
eq
(
ApolloConfig
.
class
));
HttpRequest
request
=
httpRequestArgumentCaptor
.
getValue
();
assertTrue
(
request
.
getUrl
().
contains
(
"messages=%7B%22details%22%3A%7B%22someKey%22%3A1%7D%7D"
));
}
@Test
public
void
testAssembleQueryConfigUrl
()
throws
Exception
{
Gson
gson
=
new
Gson
();
String
someUri
=
"http://someServer"
;
String
someAppId
=
"someAppId"
;
String
someCluster
=
"someCluster+ &.-_someSign"
;
String
someReleaseKey
=
"20160705193346-583078ef5716c055+20160705193308-31c471ddf9087c3f"
;
ApolloNotificationMessages
notificationMessages
=
new
ApolloNotificationMessages
();
String
someKey
=
"someKey"
;
long
someNotificationId
=
1
;
String
anotherKey
=
"anotherKey"
;
long
anotherNotificationId
=
2
;
notificationMessages
.
put
(
someKey
,
someNotificationId
);
notificationMessages
.
put
(
anotherKey
,
anotherNotificationId
);
RemoteConfigRepository
remoteConfigRepository
=
new
RemoteConfigRepository
(
someNamespace
);
ApolloConfig
someApolloConfig
=
mock
(
ApolloConfig
.
class
);
when
(
someApolloConfig
.
getReleaseKey
()).
thenReturn
(
someReleaseKey
);
String
queryConfigUrl
=
remoteConfigRepository
.
assembleQueryConfigUrl
(
someUri
,
someAppId
,
someCluster
,
someNamespace
,
null
,
.
assembleQueryConfigUrl
(
someUri
,
someAppId
,
someCluster
,
someNamespace
,
null
,
notificationMessages
,
someApolloConfig
);
remoteConfigLongPollService
.
stopLongPollingRefresh
();
...
...
@@ -200,7 +233,8 @@ public class RemoteConfigRepositoryTest {
"http://someServer/configs/someAppId/someCluster+%20&.-_someSign/"
+
someNamespace
));
assertTrue
(
queryConfigUrl
.
contains
(
"releaseKey=20160705193346-583078ef5716c055%2B20160705193308-31c471ddf9087c3f"
));
assertTrue
(
queryConfigUrl
.
contains
(
"messages="
+
UrlEscapers
.
urlFormParameterEscaper
().
escape
(
gson
.
toJson
(
notificationMessages
))));
}
private
ApolloConfig
assembleApolloConfig
(
Map
<
String
,
String
>
configurations
)
{
...
...
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAutoConfiguration.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice
;
import
com.ctrip.framework.apollo.biz.config.BizConfig
;
import
com.ctrip.framework.apollo.biz.grayReleaseRule.GrayReleaseRulesHolder
;
import
com.ctrip.framework.apollo.biz.message.ReleaseMessageScanner
;
import
com.ctrip.framework.apollo.configservice.controller.ConfigFileController
;
...
...
@@ -7,6 +8,9 @@ import com.ctrip.framework.apollo.configservice.controller.NotificationControlle
import
com.ctrip.framework.apollo.configservice.controller.NotificationControllerV2
;
import
com.ctrip.framework.apollo.configservice.service.ReleaseMessageServiceWithCache
;
import
com.ctrip.framework.apollo.configservice.service.config.ConfigService
;
import
com.ctrip.framework.apollo.configservice.service.config.ConfigServiceWithCache
;
import
com.ctrip.framework.apollo.configservice.service.config.DefaultConfigService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
...
...
@@ -16,11 +20,23 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
public
class
ConfigServiceAutoConfiguration
{
@Autowired
private
BizConfig
bizConfig
;
@Bean
public
GrayReleaseRulesHolder
grayReleaseRulesHolder
()
{
return
new
GrayReleaseRulesHolder
();
}
@Bean
public
ConfigService
configService
()
{
if
(
bizConfig
.
isConfigServiceCacheEnabled
())
{
return
new
ConfigServiceWithCache
();
}
return
new
DefaultConfigService
();
}
@Configuration
static
class
MessageScannerConfiguration
{
@Autowired
...
...
@@ -33,6 +49,8 @@ public class ConfigServiceAutoConfiguration {
private
GrayReleaseRulesHolder
grayReleaseRulesHolder
;
@Autowired
private
ReleaseMessageServiceWithCache
releaseMessageServiceWithCache
;
@Autowired
private
ConfigService
configService
;
@Bean
public
ReleaseMessageScanner
releaseMessageScanner
()
{
...
...
@@ -42,6 +60,7 @@ public class ConfigServiceAutoConfiguration {
//1. handle gray release rule
releaseMessageScanner
.
addMessageListener
(
grayReleaseRulesHolder
);
//2. handle server cache
releaseMessageScanner
.
addMessageListener
(
configService
);
releaseMessageScanner
.
addMessageListener
(
configFileController
);
//3. notify clients
releaseMessageScanner
.
addMessageListener
(
notificationControllerV2
);
...
...
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigController.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.controller
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Splitter
;
import
com.google.common.base.Strings
;
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
java.io.IOException
;
import
java.lang.reflect.Type
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.grayReleaseRule.GrayReleaseRulesHolder
;
import
com.ctrip.framework.apollo.biz.service.AppNamespaceService
;
import
com.ctrip.framework.apollo.biz.service.ReleaseService
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
import
com.ctrip.framework.apollo.configservice.util.InstanceConfigAuditUtil
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtil
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfig
;
import
com.ctrip.framework.apollo.tracer.Tracer
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.PathVariable
;
...
...
@@ -27,14 +16,24 @@ import org.springframework.web.bind.annotation.RequestMethod;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RestController
;
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.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
import
com.ctrip.framework.apollo.configservice.service.AppNamespaceServiceWithCache
;
import
com.ctrip.framework.apollo.configservice.service.config.ConfigService
;
import
com.ctrip.framework.apollo.configservice.util.InstanceConfigAuditUtil
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtil
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfig
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.ctrip.framework.apollo.tracer.Tracer
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Splitter
;
import
com.google.common.base.Strings
;
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
;
/**
* @author Jason Song(song_s@ctrip.com)
...
...
@@ -45,46 +44,46 @@ public class ConfigController {
private
static
final
Splitter
X_FORWARDED_FOR_SPLITTER
=
Splitter
.
on
(
","
).
omitEmptyStrings
()
.
trimResults
();
@Autowired
private
ReleaseService
release
Service
;
private
ConfigService
config
Service
;
@Autowired
private
AppNamespaceService
appNamespaceService
;
private
AppNamespaceService
WithCache
appNamespaceService
;
@Autowired
private
NamespaceUtil
namespaceUtil
;
@Autowired
private
InstanceConfigAuditUtil
instanceConfigAuditUtil
;
@Autowired
private
G
rayReleaseRulesHolder
grayReleaseRulesHolder
;
private
G
son
gson
;
private
static
final
Gson
gson
=
new
Gson
();
private
static
final
Type
configurationTypeReference
=
new
TypeToken
<
Map
<
java
.
lang
.
String
,
java
.
lang
.
String
>>()
{
private
static
final
Type
configurationTypeReference
=
new
TypeToken
<
Map
<
String
,
String
>>()
{
}.
getType
();
private
static
final
Joiner
STRING_JOINER
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
);
@RequestMapping
(
value
=
"/{appId}/{clusterName}/{namespace:.+}"
,
method
=
RequestMethod
.
GET
)
public
ApolloConfig
queryConfig
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
@PathVariable
String
namespace
,
@RequestParam
(
value
=
"dataCenter"
,
required
=
false
)
String
dataCenter
,
@RequestParam
(
value
=
"releaseKey"
,
defaultValue
=
"-1"
)
String
clientSideReleaseKey
,
@RequestParam
(
value
=
"dataCenter"
,
required
=
false
)
String
dataCenter
,
@RequestParam
(
value
=
"releaseKey"
,
defaultValue
=
"-1"
)
String
clientSideReleaseKey
,
@RequestParam
(
value
=
"ip"
,
required
=
false
)
String
clientIp
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
IOException
{
@RequestParam
(
value
=
"messages"
,
required
=
false
)
String
messagesAsString
,
HttpServletRe
quest
request
,
HttpServletRe
sponse
response
)
throws
IOException
{
String
originalNamespace
=
namespace
;
//strip out .properties suffix
namespace
=
namespaceUtil
.
filterNamespaceName
(
namespace
);
//fix the character case issue, such as FX.apollo <-> fx.apollo
namespace
=
namespaceUtil
.
normalizeNamespace
(
appId
,
namespace
);
if
(
Strings
.
isNullOrEmpty
(
clientIp
))
{
clientIp
=
tryToGetClientIp
(
request
);
}
ApolloNotificationMessages
clientMessages
=
transformMessages
(
messagesAsString
);
List
<
Release
>
releases
=
Lists
.
newLinkedList
();
String
appClusterNameLoaded
=
clusterName
;
if
(!
ConfigConsts
.
NO_APPID_PLACEHOLDER
.
equalsIgnoreCase
(
appId
))
{
Release
currentAppRelease
=
loadConfig
(
appId
,
clientIp
,
appId
,
clusterName
,
namespace
,
dataCenter
);
Release
currentAppRelease
=
configService
.
loadConfig
(
appId
,
clientIp
,
appId
,
clusterName
,
namespace
,
dataCenter
,
clientMessages
);
if
(
currentAppRelease
!=
null
)
{
releases
.
add
(
currentAppRelease
);
...
...
@@ -96,7 +95,7 @@ public class ConfigController {
//if namespace does not belong to this appId, should check if there is a public configuration
if
(!
namespaceBelongsToAppId
(
appId
,
namespace
))
{
Release
publicRelease
=
this
.
findPublicConfig
(
appId
,
clientIp
,
clusterName
,
namespace
,
dataCenter
);
dataCenter
,
clientMessages
);
if
(!
Objects
.
isNull
(
publicRelease
))
{
releases
.
add
(
publicRelease
);
}
...
...
@@ -145,7 +144,7 @@ public class ConfigController {
return
false
;
}
AppNamespace
appNamespace
=
appNamespaceService
.
find
On
e
(
appId
,
namespaceName
);
AppNamespace
appNamespace
=
appNamespaceService
.
find
ByAppIdAndNamespac
e
(
appId
,
namespaceName
);
return
appNamespace
!=
null
;
}
...
...
@@ -156,8 +155,7 @@ public class ConfigController {
* @param dataCenter the datacenter
*/
private
Release
findPublicConfig
(
String
clientAppId
,
String
clientIp
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
String
namespace
,
String
dataCenter
,
ApolloNotificationMessages
clientMessages
)
{
AppNamespace
appNamespace
=
appNamespaceService
.
findPublicNamespaceByName
(
namespace
);
//check whether the namespace's appId equals to current one
...
...
@@ -167,52 +165,8 @@ public class ConfigController {
String
publicConfigAppId
=
appNamespace
.
getAppId
();
return
loadConfig
(
clientAppId
,
clientIp
,
publicConfigAppId
,
clusterName
,
namespace
,
dataCenter
);
}
private
Release
loadConfig
(
String
clientAppId
,
String
clientIp
,
String
configAppId
,
String
configClusterName
,
String
configNamespace
,
String
dataCenter
)
{
//load from specified cluster fist
if
(!
Objects
.
equals
(
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
configClusterName
))
{
Release
clusterRelease
=
findRelease
(
clientAppId
,
clientIp
,
configAppId
,
configClusterName
,
configNamespace
);
if
(!
Objects
.
isNull
(
clusterRelease
))
{
return
clusterRelease
;
}
}
//try to load via data center
if
(!
Strings
.
isNullOrEmpty
(
dataCenter
)
&&
!
Objects
.
equals
(
dataCenter
,
configClusterName
))
{
Release
dataCenterRelease
=
findRelease
(
clientAppId
,
clientIp
,
configAppId
,
dataCenter
,
configNamespace
);
if
(!
Objects
.
isNull
(
dataCenterRelease
))
{
return
dataCenterRelease
;
}
}
//fallback to default release
return
findRelease
(
clientAppId
,
clientIp
,
configAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
configNamespace
);
}
private
Release
findRelease
(
String
clientAppId
,
String
clientIp
,
String
configAppId
,
String
configClusterName
,
String
configNamespace
)
{
Long
grayReleaseId
=
grayReleaseRulesHolder
.
findReleaseIdFromGrayReleaseRule
(
clientAppId
,
clientIp
,
configAppId
,
configClusterName
,
configNamespace
);
Release
release
=
null
;
if
(
grayReleaseId
!=
null
)
{
release
=
releaseService
.
findActiveOne
(
grayReleaseId
);
}
if
(
release
==
null
)
{
release
=
releaseService
.
findLatestActiveRelease
(
configAppId
,
configClusterName
,
configNamespace
);
}
return
release
;
return
configService
.
loadConfig
(
clientAppId
,
clientIp
,
publicConfigAppId
,
clusterName
,
namespace
,
dataCenter
,
clientMessages
);
}
/**
...
...
@@ -227,22 +181,22 @@ public class ConfigController {
return
result
;
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
,
String
data
c
enter
)
{
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
,
String
data
C
enter
)
{
List
<
String
>
keyParts
=
Lists
.
newArrayList
(
appId
,
cluster
,
namespace
);
if
(!
Strings
.
isNullOrEmpty
(
data
c
enter
))
{
keyParts
.
add
(
data
c
enter
);
if
(!
Strings
.
isNullOrEmpty
(
data
C
enter
))
{
keyParts
.
add
(
data
C
enter
);
}
return
STRING_JOINER
.
join
(
keyParts
);
}
private
void
auditReleases
(
String
appId
,
String
cluster
,
String
data
c
enter
,
String
clientIp
,
private
void
auditReleases
(
String
appId
,
String
cluster
,
String
data
C
enter
,
String
clientIp
,
List
<
Release
>
releases
)
{
if
(
Strings
.
isNullOrEmpty
(
clientIp
))
{
//no need to audit instance config when there is no ip
return
;
}
for
(
Release
release
:
releases
)
{
instanceConfigAuditUtil
.
audit
(
appId
,
cluster
,
data
c
enter
,
clientIp
,
release
.
getAppId
(),
instanceConfigAuditUtil
.
audit
(
appId
,
cluster
,
data
C
enter
,
clientIp
,
release
.
getAppId
(),
release
.
getClusterName
(),
release
.
getNamespaceName
(),
release
.
getReleaseKey
());
}
...
...
@@ -256,4 +210,16 @@ public class ConfigController {
return
request
.
getRemoteAddr
();
}
ApolloNotificationMessages
transformMessages
(
String
messagesAsString
)
{
ApolloNotificationMessages
notificationMessages
=
null
;
if
(!
Strings
.
isNullOrEmpty
(
messagesAsString
))
{
try
{
notificationMessages
=
gson
.
fromJson
(
messagesAsString
,
ApolloNotificationMessages
.
class
);
}
catch
(
Throwable
ex
)
{
Tracer
.
logError
(
ex
);
}
}
return
notificationMessages
;
}
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileController.java
浏览文件 @
2a834828
...
...
@@ -163,6 +163,8 @@ public class ConfigFileController implements ReleaseMessageListener {
HttpServletResponse
response
)
throws
IOException
{
//strip out .properties suffix
namespace
=
namespaceUtil
.
filterNamespaceName
(
namespace
);
//fix the character case issue, such as FX.apollo <-> fx.apollo
namespace
=
namespaceUtil
.
normalizeNamespace
(
appId
,
namespace
);
if
(
Strings
.
isNullOrEmpty
(
clientIp
))
{
clientIp
=
tryToGetClientIp
(
request
);
...
...
@@ -225,7 +227,7 @@ public class ConfigFileController implements ReleaseMessageListener {
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
IOException
{
ApolloConfig
apolloConfig
=
configController
.
queryConfig
(
appId
,
clusterName
,
namespace
,
dataCenter
,
"-1"
,
clientIp
,
request
,
response
);
dataCenter
,
"-1"
,
clientIp
,
null
,
request
,
response
);
if
(
apolloConfig
==
null
||
apolloConfig
.
getConfigurations
()
==
null
)
{
return
null
;
...
...
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationController.java
浏览文件 @
2a834828
...
...
@@ -35,6 +35,7 @@ import java.util.Set;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Deprecated
@RestController
@RequestMapping
(
"/notifications"
)
public
class
NotificationController
implements
ReleaseMessageListener
{
...
...
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationControllerV2.java
浏览文件 @
2a834828
...
...
@@ -21,6 +21,7 @@ import com.ctrip.framework.apollo.common.exception.BadRequestException;
import
com.ctrip.framework.apollo.configservice.service.ReleaseMessageServiceWithCache
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtil
;
import
com.ctrip.framework.apollo.configservice.util.WatchKeysUtil
;
import
com.ctrip.framework.apollo.configservice.wrapper.DeferredResultWrapper
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfigNotification
;
import
com.ctrip.framework.apollo.core.utils.ApolloThreadFactory
;
...
...
@@ -29,7 +30,6 @@ import com.ctrip.framework.apollo.tracer.Tracer;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.util.CollectionUtils
;
import
org.springframework.web.bind.annotation.RequestMapping
;
...
...
@@ -42,6 +42,7 @@ import java.lang.reflect.Type;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.Set
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
...
...
@@ -54,14 +55,10 @@ import java.util.concurrent.TimeUnit;
@RequestMapping
(
"/notifications/v2"
)
public
class
NotificationControllerV2
implements
ReleaseMessageListener
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
NotificationControllerV2
.
class
);
private
static
final
long
TIMEOUT
=
30
*
1000
;
//30 seconds
private
final
Multimap
<
String
,
DeferredResult
<
ResponseEntity
<
List
<
ApolloConfigNotification
>>>>
deferredResults
=
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.
create
());
private
static
final
ResponseEntity
<
List
<
ApolloConfigNotification
>>
NOT_MODIFIED_RESPONSE_LIST
=
new
ResponseEntity
<>(
HttpStatus
.
NOT_MODIFIED
);
private
final
Multimap
<
String
,
DeferredResultWrapper
>
deferredResults
=
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.
create
());
private
static
final
Splitter
STRING_SPLITTER
=
Splitter
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
).
omitEmptyStrings
();
private
static
final
long
NOTIFICATION_ID_PLACEHOLDER
=
-
1
;
private
static
final
Type
notificationsTypeReference
=
new
TypeToken
<
List
<
ApolloConfigNotification
>>()
{
}.
getType
();
...
...
@@ -111,16 +108,19 @@ public class NotificationControllerV2 implements ReleaseMessageListener {
throw
new
BadRequestException
(
"Invalid format of notifications: "
+
notificationsAsString
);
}
DeferredResultWrapper
deferredResultWrapper
=
new
DeferredResultWrapper
();
Set
<
String
>
namespaces
=
Sets
.
newHashSet
();
Map
<
String
,
Long
>
clientSideNotifications
=
Maps
.
newHashMap
();
for
(
ApolloConfigNotification
notification
:
notifications
)
{
if
(
Strings
.
isNullOrEmpty
(
notification
.
getNamespaceName
()))
{
continue
;
Map
<
String
,
ApolloConfigNotification
>
filteredNotifications
=
filterNotifications
(
appId
,
notifications
);
for
(
Map
.
Entry
<
String
,
ApolloConfigNotification
>
notificationEntry
:
filteredNotifications
.
entrySet
())
{
String
normalizedNamespace
=
notificationEntry
.
getKey
();
ApolloConfigNotification
notification
=
notificationEntry
.
getValue
();
namespaces
.
add
(
normalizedNamespace
);
clientSideNotifications
.
put
(
normalizedNamespace
,
notification
.
getNotificationId
());
if
(!
Objects
.
equals
(
notification
.
getNamespaceName
(),
normalizedNamespace
))
{
deferredResultWrapper
.
recordNamespaceNameNormalizedResult
(
notification
.
getNamespaceName
(),
normalizedNamespace
);
}
//strip out .properties suffix
String
namespace
=
namespaceUtil
.
filterNamespaceName
(
notification
.
getNamespaceName
());
namespaces
.
add
(
namespace
);
clientSideNotifications
.
put
(
namespace
,
notification
.
getNotificationId
());
}
if
(
CollectionUtils
.
isEmpty
(
namespaces
))
{
...
...
@@ -130,9 +130,6 @@ public class NotificationControllerV2 implements ReleaseMessageListener {
Multimap
<
String
,
String
>
watchedKeysMap
=
watchKeysUtil
.
assembleAllWatchKeys
(
appId
,
cluster
,
namespaces
,
dataCenter
);
DeferredResult
<
ResponseEntity
<
List
<
ApolloConfigNotification
>>>
deferredResult
=
new
DeferredResult
<>(
TIMEOUT
,
NOT_MODIFIED_RESPONSE_LIST
);
Set
<
String
>
watchedKeys
=
Sets
.
newHashSet
(
watchedKeysMap
.
values
());
List
<
ReleaseMessage
>
latestReleaseMessages
=
...
...
@@ -151,20 +148,20 @@ public class NotificationControllerV2 implements ReleaseMessageListener {
latestReleaseMessages
);
if
(!
CollectionUtils
.
isEmpty
(
newNotifications
))
{
deferredResult
.
setResult
(
new
ResponseEntity
<>(
newNotifications
,
HttpStatus
.
OK
)
);
deferredResult
Wrapper
.
setResult
(
newNotifications
);
}
else
{
//register all keys
for
(
String
key
:
watchedKeys
)
{
this
.
deferredResults
.
put
(
key
,
deferredResult
);
this
.
deferredResults
.
put
(
key
,
deferredResult
Wrapper
);
}
deferredResult
deferredResult
Wrapper
.
onTimeout
(()
->
logWatchedKeys
(
watchedKeys
,
"Apollo.LongPoll.TimeOutKeys"
));
deferredResult
.
onCompletion
(()
->
{
deferredResult
Wrapper
.
onCompletion
(()
->
{
//unregister all keys
for
(
String
key
:
watchedKeys
)
{
deferredResults
.
remove
(
key
,
deferredResult
);
deferredResults
.
remove
(
key
,
deferredResult
Wrapper
);
}
logWatchedKeys
(
watchedKeys
,
"Apollo.LongPoll.CompletedKeys"
);
});
...
...
@@ -174,7 +171,33 @@ public class NotificationControllerV2 implements ReleaseMessageListener {
watchedKeys
,
appId
,
cluster
,
namespaces
,
dataCenter
);
}
return
deferredResult
;
return
deferredResultWrapper
.
getResult
();
}
private
Map
<
String
,
ApolloConfigNotification
>
filterNotifications
(
String
appId
,
List
<
ApolloConfigNotification
>
notifications
)
{
Map
<
String
,
ApolloConfigNotification
>
filteredNotifications
=
Maps
.
newHashMap
();
for
(
ApolloConfigNotification
notification
:
notifications
)
{
if
(
Strings
.
isNullOrEmpty
(
notification
.
getNamespaceName
()))
{
continue
;
}
//strip out .properties suffix
String
originalNamespace
=
namespaceUtil
.
filterNamespaceName
(
notification
.
getNamespaceName
());
notification
.
setNamespaceName
(
originalNamespace
);
//fix the character case issue, such as FX.apollo <-> fx.apollo
String
normalizedNamespace
=
namespaceUtil
.
normalizeNamespace
(
appId
,
originalNamespace
);
// in case client side namespace name has character case issue and has difference notification ids
// such as FX.apollo = 1 but fx.apollo = 2, we should let FX.apollo have the chance to update its notification id
// which means we should record FX.apollo = 1 here and ignore fx.apollo = 2
if
(
filteredNotifications
.
containsKey
(
normalizedNamespace
)
&&
filteredNotifications
.
get
(
normalizedNamespace
).
getNotificationId
()
<
notification
.
getNotificationId
())
{
continue
;
}
filteredNotifications
.
put
(
normalizedNamespace
,
notification
);
}
return
filteredNotifications
;
}
private
List
<
ApolloConfigNotification
>
getApolloConfigNotifications
(
Set
<
String
>
namespaces
,
...
...
@@ -190,17 +213,20 @@ public class NotificationControllerV2 implements ReleaseMessageListener {
for
(
String
namespace
:
namespaces
)
{
long
clientSideId
=
clientSideNotifications
.
get
(
namespace
);
long
latestId
=
NOTIFICATION_ID_PLACEHOLDER
;
long
latestId
=
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
;
Collection
<
String
>
namespaceWatchedKeys
=
watchedKeysMap
.
get
(
namespace
);
for
(
String
namespaceWatchedKey
:
namespaceWatchedKeys
)
{
long
namespaceNotificationId
=
latestNotifications
.
getOrDefault
(
namespaceWatchedKey
,
NOTIFICATION_ID_PLACEHOLDER
);
latestNotifications
.
getOrDefault
(
namespaceWatchedKey
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
);
if
(
namespaceNotificationId
>
latestId
)
{
latestId
=
namespaceNotificationId
;
}
}
if
(
latestId
>
clientSideId
)
{
newNotifications
.
add
(
new
ApolloConfigNotification
(
namespace
,
latestId
));
ApolloConfigNotification
notification
=
new
ApolloConfigNotification
(
namespace
,
latestId
);
namespaceWatchedKeys
.
stream
().
filter
(
latestNotifications:
:
containsKey
).
forEach
(
namespaceWatchedKey
->
notification
.
addMessage
(
namespaceWatchedKey
,
latestNotifications
.
get
(
namespaceWatchedKey
)));
newNotifications
.
add
(
notification
);
}
}
}
...
...
@@ -224,17 +250,15 @@ public class NotificationControllerV2 implements ReleaseMessageListener {
return
;
}
ResponseEntity
<
List
<
ApolloConfigNotification
>>
notification
=
new
ResponseEntity
<>(
Lists
.
newArrayList
(
new
ApolloConfigNotification
(
changedNamespace
,
message
.
getId
())),
HttpStatus
.
OK
);
if
(!
deferredResults
.
containsKey
(
content
))
{
return
;
}
//create a new list to avoid ConcurrentModificationException
List
<
DeferredResult
<
ResponseEntity
<
List
<
ApolloConfigNotification
>>>>
results
=
Lists
.
newArrayList
(
deferredResults
.
get
(
content
));
List
<
DeferredResultWrapper
>
results
=
Lists
.
newArrayList
(
deferredResults
.
get
(
content
));
ApolloConfigNotification
configNotification
=
new
ApolloConfigNotification
(
changedNamespace
,
message
.
getId
());
configNotification
.
addMessage
(
content
,
message
.
getId
());
//do async notification if too many clients
if
(
results
.
size
()
>
bizConfig
.
releaseMessageNotificationBatch
())
{
...
...
@@ -250,7 +274,7 @@ public class NotificationControllerV2 implements ReleaseMessageListener {
}
}
logger
.
debug
(
"Async notify {}"
,
results
.
get
(
i
));
results
.
get
(
i
).
setResult
(
n
otification
);
results
.
get
(
i
).
setResult
(
configN
otification
);
}
});
return
;
...
...
@@ -258,8 +282,8 @@ public class NotificationControllerV2 implements ReleaseMessageListener {
logger
.
debug
(
"Notify {} clients for key {}"
,
results
.
size
(),
content
);
for
(
DeferredResult
<
ResponseEntity
<
List
<
ApolloConfigNotification
>>>
result
:
results
)
{
result
.
setResult
(
n
otification
);
for
(
DeferredResult
Wrapper
result
:
results
)
{
result
.
setResult
(
configN
otification
);
}
logger
.
debug
(
"Notification completed"
);
}
...
...
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/AppNamespaceServiceWithCache.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.service
;
import
com.ctrip.framework.apollo.configservice.wrapper.CaseInsensitiveMapWrapper
;
import
com.ctrip.framework.apollo.core.utils.StringUtils
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Preconditions
;
import
com.google.common.base.Strings
;
...
...
@@ -52,29 +54,37 @@ public class AppNamespaceServiceWithCache implements InitializingBean {
private
long
maxIdScanned
;
//store namespaceName -> AppNamespace
private
Map
<
String
,
AppNamespace
>
publicAppNamespaceCache
;
private
CaseInsensitiveMapWrapper
<
AppNamespace
>
publicAppNamespaceCache
;
//store appId+namespaceName -> AppNamespace
private
Map
<
String
,
AppNamespace
>
appNamespaceCache
;
private
CaseInsensitiveMapWrapper
<
AppNamespace
>
appNamespaceCache
;
//store id -> AppNamespace
private
Map
<
Long
,
AppNamespace
>
appNamespaceIdCache
;
public
AppNamespaceServiceWithCache
()
{
initialize
();
}
private
void
initialize
()
{
maxIdScanned
=
0
;
publicAppNamespaceCache
=
Maps
.
newConcurrentMap
(
);
appNamespaceCache
=
Maps
.
newConcurrentMap
(
);
publicAppNamespaceCache
=
new
CaseInsensitiveMapWrapper
<>(
Maps
.
newConcurrentMap
()
);
appNamespaceCache
=
new
CaseInsensitiveMapWrapper
<>(
Maps
.
newConcurrentMap
()
);
appNamespaceIdCache
=
Maps
.
newConcurrentMap
();
scheduledExecutorService
=
Executors
.
newScheduledThreadPool
(
1
,
ApolloThreadFactory
.
create
(
"AppNamespaceServiceWithCache"
,
true
));
}
public
AppNamespace
findByAppIdAndNamespace
(
String
appId
,
String
namespaceName
)
{
Preconditions
.
checkArgument
(!
StringUtils
.
isContainEmpty
(
appId
,
namespaceName
),
"appId and namespaceName must not be empty"
);
return
appNamespaceCache
.
get
(
STRING_JOINER
.
join
(
appId
,
namespaceName
));
}
public
List
<
AppNamespace
>
findByAppIdAndNamespaces
(
String
appId
,
Set
<
String
>
namespaceNames
)
{
Preconditions
.
checkArgument
(!
Strings
.
isNullOrEmpty
(
appId
),
"appId must not be null"
);
if
(
namespaceNames
==
null
||
namespaceNames
.
isEmpty
())
{
return
Collections
.
emptyList
();
}
// return appNamespaceRepository.findByAppIdAndNameIn(appId, namespaceNames);
List
<
AppNamespace
>
result
=
Lists
.
newArrayList
();
for
(
String
namespaceName
:
namespaceNames
)
{
AppNamespace
appNamespace
=
appNamespaceCache
.
get
(
STRING_JOINER
.
join
(
appId
,
namespaceName
));
...
...
@@ -85,12 +95,16 @@ public class AppNamespaceServiceWithCache implements InitializingBean {
return
result
;
}
public
AppNamespace
findPublicNamespaceByName
(
String
namespaceName
)
{
Preconditions
.
checkArgument
(!
Strings
.
isNullOrEmpty
(
namespaceName
),
"namespaceName must not be empty"
);
return
publicAppNamespaceCache
.
get
(
namespaceName
);
}
public
List
<
AppNamespace
>
findPublicNamespacesByNames
(
Set
<
String
>
namespaceNames
)
{
if
(
namespaceNames
==
null
||
namespaceNames
.
isEmpty
())
{
return
Collections
.
emptyList
();
}
// return appNamespaceRepository.findByNameInAndIsPublicTrue(namespaceNames);
List
<
AppNamespace
>
result
=
Lists
.
newArrayList
();
for
(
String
namespaceName
:
namespaceNames
)
{
AppNamespace
appNamespace
=
publicAppNamespaceCache
.
get
(
namespaceName
);
...
...
@@ -249,4 +263,11 @@ public class AppNamespaceServiceWithCache implements InitializingBean {
rebuildInterval
=
bizConfig
.
appNamespaceCacheRebuildInterval
();
rebuildIntervalTimeUnit
=
bizConfig
.
appNamespaceCacheRebuildIntervalTimeUnit
();
}
//only for test use
private
void
reset
()
throws
Exception
{
scheduledExecutorService
.
shutdownNow
();
initialize
();
afterPropertiesSet
();
}
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/AbstractConfigService.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.service.config
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.grayReleaseRule.GrayReleaseRulesHolder
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.google.common.base.Strings
;
import
java.util.Map
;
import
java.util.Objects
;
import
org.springframework.beans.factory.annotation.Autowired
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
abstract
class
AbstractConfigService
implements
ConfigService
{
@Autowired
private
GrayReleaseRulesHolder
grayReleaseRulesHolder
;
@Override
public
Release
loadConfig
(
String
clientAppId
,
String
clientIp
,
String
configAppId
,
String
configClusterName
,
String
configNamespace
,
String
dataCenter
,
ApolloNotificationMessages
clientMessages
)
{
// load from specified cluster fist
if
(!
Objects
.
equals
(
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
configClusterName
))
{
Release
clusterRelease
=
findRelease
(
clientAppId
,
clientIp
,
configAppId
,
configClusterName
,
configNamespace
,
clientMessages
);
if
(!
Objects
.
isNull
(
clusterRelease
))
{
return
clusterRelease
;
}
}
// try to load via data center
if
(!
Strings
.
isNullOrEmpty
(
dataCenter
)
&&
!
Objects
.
equals
(
dataCenter
,
configClusterName
))
{
Release
dataCenterRelease
=
findRelease
(
clientAppId
,
clientIp
,
configAppId
,
dataCenter
,
configNamespace
,
clientMessages
);
if
(!
Objects
.
isNull
(
dataCenterRelease
))
{
return
dataCenterRelease
;
}
}
// fallback to default release
return
findRelease
(
clientAppId
,
clientIp
,
configAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
configNamespace
,
clientMessages
);
}
/**
* Find release
*
* @param clientAppId the client's app id
* @param clientIp the client ip
* @param configAppId the requested config's app id
* @param configClusterName the requested config's cluster name
* @param configNamespace the requested config's namespace name
* @param clientMessages the messages received in client side
* @return the release
*/
private
Release
findRelease
(
String
clientAppId
,
String
clientIp
,
String
configAppId
,
String
configClusterName
,
String
configNamespace
,
ApolloNotificationMessages
clientMessages
)
{
Long
grayReleaseId
=
grayReleaseRulesHolder
.
findReleaseIdFromGrayReleaseRule
(
clientAppId
,
clientIp
,
configAppId
,
configClusterName
,
configNamespace
);
Release
release
=
null
;
if
(
grayReleaseId
!=
null
)
{
release
=
findActiveOne
(
grayReleaseId
,
clientMessages
);
}
if
(
release
==
null
)
{
release
=
findLatestActiveRelease
(
configAppId
,
configClusterName
,
configNamespace
,
clientMessages
);
}
return
release
;
}
/**
* Find active release by id
*/
protected
abstract
Release
findActiveOne
(
long
id
,
ApolloNotificationMessages
clientMessages
);
/**
* Find active release by app id, cluster name and namespace name
*/
protected
abstract
Release
findLatestActiveRelease
(
String
configAppId
,
String
configClusterName
,
String
configNamespaceName
,
ApolloNotificationMessages
clientMessages
);
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/ConfigService.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.service.config
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.message.ReleaseMessageListener
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
interface
ConfigService
extends
ReleaseMessageListener
{
/**
* Load config
*
* @param clientAppId the client's app id
* @param clientIp the client ip
* @param configAppId the requested config's app id
* @param configClusterName the requested config's cluster name
* @param configNamespace the requested config's namespace name
* @param dataCenter the client data center
* @param clientMessages the messages received in client side
* @return the Release
*/
Release
loadConfig
(
String
clientAppId
,
String
clientIp
,
String
configAppId
,
String
configClusterName
,
String
configNamespace
,
String
dataCenter
,
ApolloNotificationMessages
clientMessages
);
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/ConfigServiceWithCache.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.service.config
;
import
com.google.common.base.Splitter
;
import
com.google.common.base.Strings
;
import
com.google.common.cache.CacheBuilder
;
import
com.google.common.cache.CacheLoader
;
import
com.google.common.cache.LoadingCache
;
import
com.google.common.collect.Lists
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.framework.apollo.biz.message.Topics
;
import
com.ctrip.framework.apollo.biz.service.ReleaseMessageService
;
import
com.ctrip.framework.apollo.biz.service.ReleaseService
;
import
com.ctrip.framework.apollo.biz.utils.ReleaseMessageKeyGenerator
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.ctrip.framework.apollo.tracer.Tracer
;
import
com.ctrip.framework.apollo.tracer.spi.Transaction
;
import
java.util.Optional
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
java.util.List
;
import
java.util.concurrent.TimeUnit
;
import
javax.annotation.PostConstruct
;
/**
* config service with guava cache
*
* @author Jason Song(song_s@ctrip.com)
*/
public
class
ConfigServiceWithCache
extends
AbstractConfigService
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
ConfigServiceWithCache
.
class
);
private
static
final
long
DEFAULT_EXPIRED_AFTER_ACCESS_IN_MINUTES
=
60
;
//1 hour
private
static
final
String
TRACER_EVENT_CACHE_INVALIDATE
=
"ConfigCache.Invalidate"
;
private
static
final
String
TRACER_EVENT_CACHE_LOAD
=
"ConfigCache.LoadFromDB"
;
private
static
final
String
TRACER_EVENT_CACHE_LOAD_ID
=
"ConfigCache.LoadFromDBById"
;
private
static
final
String
TRACER_EVENT_CACHE_GET
=
"ConfigCache.Get"
;
private
static
final
String
TRACER_EVENT_CACHE_GET_ID
=
"ConfigCache.GetById"
;
private
static
final
Splitter
STRING_SPLITTER
=
Splitter
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
).
omitEmptyStrings
();
@Autowired
private
ReleaseService
releaseService
;
@Autowired
private
ReleaseMessageService
releaseMessageService
;
private
LoadingCache
<
String
,
ConfigCacheEntry
>
configCache
;
private
LoadingCache
<
Long
,
Optional
<
Release
>>
configIdCache
;
private
ConfigCacheEntry
nullConfigCacheEntry
;
public
ConfigServiceWithCache
()
{
nullConfigCacheEntry
=
new
ConfigCacheEntry
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
null
);
}
@PostConstruct
void
initialize
()
{
configCache
=
CacheBuilder
.
newBuilder
()
.
expireAfterAccess
(
DEFAULT_EXPIRED_AFTER_ACCESS_IN_MINUTES
,
TimeUnit
.
MINUTES
)
.
build
(
new
CacheLoader
<
String
,
ConfigCacheEntry
>()
{
@Override
public
ConfigCacheEntry
load
(
String
key
)
throws
Exception
{
List
<
String
>
namespaceInfo
=
STRING_SPLITTER
.
splitToList
(
key
);
if
(
namespaceInfo
.
size
()
!=
3
)
{
Tracer
.
logError
(
new
IllegalArgumentException
(
String
.
format
(
"Invalid cache load key %s"
,
key
)));
return
nullConfigCacheEntry
;
}
Transaction
transaction
=
Tracer
.
newTransaction
(
TRACER_EVENT_CACHE_LOAD
,
key
);
try
{
ReleaseMessage
latestReleaseMessage
=
releaseMessageService
.
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
key
));
Release
latestRelease
=
releaseService
.
findLatestActiveRelease
(
namespaceInfo
.
get
(
0
),
namespaceInfo
.
get
(
1
),
namespaceInfo
.
get
(
2
));
transaction
.
setStatus
(
Transaction
.
SUCCESS
);
long
notificationId
=
latestReleaseMessage
==
null
?
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
:
latestReleaseMessage
.
getId
();
if
(
notificationId
==
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
&&
latestRelease
==
null
)
{
return
nullConfigCacheEntry
;
}
return
new
ConfigCacheEntry
(
notificationId
,
latestRelease
);
}
catch
(
Throwable
ex
)
{
transaction
.
setStatus
(
ex
);
throw
ex
;
}
finally
{
transaction
.
complete
();
}
}
});
configIdCache
=
CacheBuilder
.
newBuilder
()
.
expireAfterAccess
(
DEFAULT_EXPIRED_AFTER_ACCESS_IN_MINUTES
,
TimeUnit
.
MINUTES
)
.
build
(
new
CacheLoader
<
Long
,
Optional
<
Release
>>()
{
@Override
public
Optional
<
Release
>
load
(
Long
key
)
throws
Exception
{
Transaction
transaction
=
Tracer
.
newTransaction
(
TRACER_EVENT_CACHE_LOAD_ID
,
String
.
valueOf
(
key
));
try
{
Release
release
=
releaseService
.
findActiveOne
(
key
);
transaction
.
setStatus
(
Transaction
.
SUCCESS
);
return
Optional
.
ofNullable
(
release
);
}
catch
(
Throwable
ex
)
{
transaction
.
setStatus
(
ex
);
throw
ex
;
}
finally
{
transaction
.
complete
();
}
}
});
}
@Override
protected
Release
findActiveOne
(
long
id
,
ApolloNotificationMessages
clientMessages
)
{
Tracer
.
logEvent
(
TRACER_EVENT_CACHE_GET_ID
,
String
.
valueOf
(
id
));
return
configIdCache
.
getUnchecked
(
id
).
orElse
(
null
);
}
@Override
protected
Release
findLatestActiveRelease
(
String
appId
,
String
clusterName
,
String
namespaceName
,
ApolloNotificationMessages
clientMessages
)
{
String
key
=
ReleaseMessageKeyGenerator
.
generate
(
appId
,
clusterName
,
namespaceName
);
Tracer
.
logEvent
(
TRACER_EVENT_CACHE_GET
,
key
);
ConfigCacheEntry
cacheEntry
=
configCache
.
getUnchecked
(
key
);
//cache is out-dated
if
(
clientMessages
!=
null
&&
clientMessages
.
has
(
key
)
&&
clientMessages
.
get
(
key
)
>
cacheEntry
.
getNotificationId
())
{
//invalidate the cache and try to load from db again
invalidate
(
key
);
cacheEntry
=
configCache
.
getUnchecked
(
key
);
}
return
cacheEntry
.
getRelease
();
}
private
void
invalidate
(
String
key
)
{
configCache
.
invalidate
(
key
);
Tracer
.
logEvent
(
TRACER_EVENT_CACHE_INVALIDATE
,
key
);
}
@Override
public
void
handleMessage
(
ReleaseMessage
message
,
String
channel
)
{
logger
.
info
(
"message received - channel: {}, message: {}"
,
channel
,
message
);
if
(!
Topics
.
APOLLO_RELEASE_TOPIC
.
equals
(
channel
)
||
Strings
.
isNullOrEmpty
(
message
.
getMessage
()))
{
return
;
}
try
{
invalidate
(
message
.
getMessage
());
//warm up the cache
configCache
.
getUnchecked
(
message
.
getMessage
());
}
catch
(
Throwable
ex
)
{
//ignore
}
}
private
static
class
ConfigCacheEntry
{
private
final
long
notificationId
;
private
final
Release
release
;
public
ConfigCacheEntry
(
long
notificationId
,
Release
release
)
{
this
.
notificationId
=
notificationId
;
this
.
release
=
release
;
}
public
long
getNotificationId
()
{
return
notificationId
;
}
public
Release
getRelease
()
{
return
release
;
}
}
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/DefaultConfigService.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.service.config
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.framework.apollo.biz.service.ReleaseService
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
org.springframework.beans.factory.annotation.Autowired
;
/**
* config service with no cache
*
* @author Jason Song(song_s@ctrip.com)
*/
public
class
DefaultConfigService
extends
AbstractConfigService
{
@Autowired
private
ReleaseService
releaseService
;
@Override
protected
Release
findActiveOne
(
long
id
,
ApolloNotificationMessages
clientMessages
)
{
return
releaseService
.
findActiveOne
(
id
);
}
@Override
protected
Release
findLatestActiveRelease
(
String
configAppId
,
String
configClusterName
,
String
configNamespace
,
ApolloNotificationMessages
clientMessages
)
{
return
releaseService
.
findLatestActiveRelease
(
configAppId
,
configClusterName
,
configNamespace
);
}
@Override
public
void
handleMessage
(
ReleaseMessage
message
,
String
channel
)
{
// since there is no cache, so do nothing
}
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/util/NamespaceUtil.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.util
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
import
com.ctrip.framework.apollo.configservice.service.AppNamespaceServiceWithCache
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
/**
...
...
@@ -8,6 +12,9 @@ import org.springframework.stereotype.Component;
@Component
public
class
NamespaceUtil
{
@Autowired
private
AppNamespaceServiceWithCache
appNamespaceServiceWithCache
;
public
String
filterNamespaceName
(
String
namespaceName
)
{
if
(
namespaceName
.
toLowerCase
().
endsWith
(
".properties"
))
{
int
dotIndex
=
namespaceName
.
lastIndexOf
(
"."
);
...
...
@@ -16,4 +23,18 @@ public class NamespaceUtil {
return
namespaceName
;
}
public
String
normalizeNamespace
(
String
appId
,
String
namespaceName
)
{
AppNamespace
appNamespace
=
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
appId
,
namespaceName
);
if
(
appNamespace
!=
null
)
{
return
appNamespace
.
getName
();
}
appNamespace
=
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
namespaceName
);
if
(
appNamespace
!=
null
)
{
return
appNamespace
.
getName
();
}
return
namespaceName
;
}
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/wrapper/CaseInsensitiveMapWrapper.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.wrapper
;
import
java.util.Map
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
CaseInsensitiveMapWrapper
<
T
>
{
private
final
Map
<
String
,
T
>
delegate
;
public
CaseInsensitiveMapWrapper
(
Map
<
String
,
T
>
delegate
)
{
this
.
delegate
=
delegate
;
}
public
T
get
(
String
key
)
{
return
delegate
.
get
(
key
.
toLowerCase
());
}
public
T
put
(
String
key
,
T
value
)
{
return
delegate
.
put
(
key
.
toLowerCase
(),
value
);
}
public
T
remove
(
String
key
)
{
return
delegate
.
remove
(
key
.
toLowerCase
());
}
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/wrapper/DeferredResultWrapper.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.wrapper
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Maps
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfig
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfigNotification
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.context.request.async.DeferredResult
;
import
java.util.List
;
import
java.util.Map
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
DeferredResultWrapper
{
private
static
final
long
TIMEOUT
=
30
*
1000
;
//30 seconds
private
static
final
ResponseEntity
<
List
<
ApolloConfigNotification
>>
NOT_MODIFIED_RESPONSE_LIST
=
new
ResponseEntity
<>(
HttpStatus
.
NOT_MODIFIED
);
private
Map
<
String
,
String
>
normalizedNamespaceNameToOriginalNamespaceName
;
private
DeferredResult
<
ResponseEntity
<
List
<
ApolloConfigNotification
>>>
result
;
public
DeferredResultWrapper
()
{
result
=
new
DeferredResult
<>(
TIMEOUT
,
NOT_MODIFIED_RESPONSE_LIST
);
}
public
void
recordNamespaceNameNormalizedResult
(
String
originalNamespaceName
,
String
normalizedNamespaceName
)
{
if
(
normalizedNamespaceNameToOriginalNamespaceName
==
null
)
{
normalizedNamespaceNameToOriginalNamespaceName
=
Maps
.
newHashMap
();
}
normalizedNamespaceNameToOriginalNamespaceName
.
put
(
normalizedNamespaceName
,
originalNamespaceName
);
}
public
void
onTimeout
(
Runnable
timeoutCallback
)
{
result
.
onTimeout
(
timeoutCallback
);
}
public
void
onCompletion
(
Runnable
completionCallback
)
{
result
.
onCompletion
(
completionCallback
);
}
public
void
setResult
(
ApolloConfigNotification
notification
)
{
setResult
(
Lists
.
newArrayList
(
notification
));
}
/**
* The namespace name is used as a key in client side, so we have to return the original one instead of the correct one
*/
public
void
setResult
(
List
<
ApolloConfigNotification
>
notifications
)
{
if
(
normalizedNamespaceNameToOriginalNamespaceName
!=
null
)
{
notifications
.
stream
().
filter
(
notification
->
normalizedNamespaceNameToOriginalNamespaceName
.
containsKey
(
notification
.
getNamespaceName
())).
forEach
(
notification
->
notification
.
setNamespaceName
(
normalizedNamespaceNameToOriginalNamespaceName
.
get
(
notification
.
getNamespaceName
())));
}
result
.
setResult
(
new
ResponseEntity
<>(
notifications
,
HttpStatus
.
OK
));
}
public
DeferredResult
<
ResponseEntity
<
List
<
ApolloConfigNotification
>>>
getResult
()
{
return
result
;
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/AllTests.java
浏览文件 @
2a834828
...
...
@@ -10,9 +10,12 @@ import com.ctrip.framework.apollo.configservice.integration.NotificationControll
import
com.ctrip.framework.apollo.configservice.integration.NotificationControllerV2IntegrationTest
;
import
com.ctrip.framework.apollo.configservice.service.AppNamespaceServiceWithCacheTest
;
import
com.ctrip.framework.apollo.configservice.service.ReleaseMessageServiceWithCacheTest
;
import
com.ctrip.framework.apollo.configservice.service.config.ConfigServiceWithCacheTest
;
import
com.ctrip.framework.apollo.configservice.service.config.DefaultConfigServiceTest
;
import
com.ctrip.framework.apollo.configservice.util.InstanceConfigAuditUtilTest
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtilTest
;
import
com.ctrip.framework.apollo.configservice.util.WatchKeysUtilTest
;
import
com.ctrip.framework.apollo.configservice.wrapper.CaseInsensitiveMapWrapperTest
;
import
org.junit.runner.RunWith
;
import
org.junit.runners.Suite
;
...
...
@@ -25,7 +28,8 @@ import org.junit.runners.Suite.SuiteClasses;
ConfigFileControllerIntegrationTest
.
class
,
WatchKeysUtilTest
.
class
,
NotificationControllerV2Test
.
class
,
NotificationControllerV2IntegrationTest
.
class
,
InstanceConfigAuditUtilTest
.
class
,
AppNamespaceServiceWithCacheTest
.
class
,
ReleaseMessageServiceWithCacheTest
.
class
ReleaseMessageServiceWithCacheTest
.
class
,
DefaultConfigServiceTest
.
class
,
ConfigServiceWithCacheTest
.
class
,
CaseInsensitiveMapWrapperTest
.
class
})
public
class
AllTests
{
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigControllerTest.java
浏览文件 @
2a834828
此差异已折叠。
点击以展开。
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileControllerTest.java
浏览文件 @
2a834828
...
...
@@ -80,6 +80,7 @@ public class ConfigFileControllerTest {
someClientIp
=
"10.1.1.1"
;
when
(
namespaceUtil
.
filterNamespaceName
(
someNamespace
)).
thenReturn
(
someNamespace
);
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
someNamespace
)).
thenReturn
(
someNamespace
);
when
(
grayReleaseRulesHolder
.
hasGrayReleaseRule
(
anyString
(),
anyString
(),
anyString
()))
.
thenReturn
(
false
);
...
...
@@ -111,7 +112,7 @@ public class ConfigFileControllerTest {
ApolloConfig
someApolloConfig
=
mock
(
ApolloConfig
.
class
);
when
(
someApolloConfig
.
getConfigurations
()).
thenReturn
(
configurations
);
when
(
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
null
,
someRequest
,
someResponse
)).
thenReturn
(
someApolloConfig
);
when
(
watchKeysUtil
.
assembleAllWatchKeys
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
))
...
...
@@ -141,7 +142,7 @@ public class ConfigFileControllerTest {
assertEquals
(
response
,
anotherResponse
);
verify
(
configController
,
times
(
1
))
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
null
,
someRequest
,
someResponse
);
}
...
...
@@ -159,7 +160,7 @@ public class ConfigFileControllerTest {
ImmutableMap
.
of
(
someKey
,
someValue
);
ApolloConfig
someApolloConfig
=
mock
(
ApolloConfig
.
class
);
when
(
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
null
,
someRequest
,
someResponse
)).
thenReturn
(
someApolloConfig
);
when
(
someApolloConfig
.
getConfigurations
()).
thenReturn
(
configurations
);
when
(
watchKeysUtil
...
...
@@ -191,7 +192,7 @@ public class ConfigFileControllerTest {
ApolloConfig
someApolloConfig
=
mock
(
ApolloConfig
.
class
);
when
(
someApolloConfig
.
getConfigurations
()).
thenReturn
(
configurations
);
when
(
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
null
,
someRequest
,
someResponse
)).
thenReturn
(
someApolloConfig
);
ResponseEntity
<
String
>
response
=
...
...
@@ -205,7 +206,7 @@ public class ConfigFileControllerTest {
someClientIp
,
someRequest
,
someResponse
);
verify
(
configController
,
times
(
2
))
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
null
,
someRequest
,
someResponse
);
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/NotificationControllerV2Test.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.controller
;
import
com.ctrip.framework.apollo.configservice.wrapper.DeferredResultWrapper
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.google.common.base.Joiner
;
import
com.google.common.collect.HashMultimap
;
import
com.google.common.collect.Lists
;
...
...
@@ -27,7 +29,9 @@ import org.springframework.http.ResponseEntity;
import
org.springframework.test.util.ReflectionTestUtils
;
import
org.springframework.web.context.request.async.DeferredResult
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.concurrent.TimeUnit
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
...
...
@@ -64,8 +68,7 @@ public class NotificationControllerV2Test {
private
Gson
gson
;
private
Multimap
<
String
,
DeferredResult
<
ResponseEntity
<
List
<
ApolloConfigNotification
>>>>
deferredResults
;
private
Multimap
<
String
,
DeferredResultWrapper
>
deferredResults
;
@Before
public
void
setUp
()
throws
Exception
{
...
...
@@ -93,10 +96,11 @@ public class NotificationControllerV2Test {
when
(
namespaceUtil
.
filterNamespaceName
(
defaultNamespace
)).
thenReturn
(
defaultNamespace
);
when
(
namespaceUtil
.
filterNamespaceName
(
somePublicNamespace
)).
thenReturn
(
somePublicNamespace
);
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
defaultNamespace
)).
thenReturn
(
defaultNamespace
);
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
somePublicNamespace
)).
thenReturn
(
somePublicNamespace
);
deferredResults
=
(
Multimap
<
String
,
DeferredResult
<
ResponseEntity
<
List
<
ApolloConfigNotification
>>>>)
ReflectionTestUtils
.
getField
(
controller
,
"deferredResults"
);
(
Multimap
<
String
,
DeferredResultWrapper
>)
ReflectionTestUtils
.
getField
(
controller
,
"deferredResults"
);
}
@Test
...
...
@@ -122,9 +126,7 @@ public class NotificationControllerV2Test {
assertEquals
(
watchKeysMap
.
size
(),
deferredResults
.
size
());
for
(
String
watchKey
:
watchKeysMap
.
values
())
{
assertTrue
(
deferredResults
.
get
(
watchKey
).
contains
(
deferredResult
));
}
assertWatchKeys
(
watchKeysMap
,
deferredResult
);
}
@Test
...
...
@@ -153,9 +155,7 @@ public class NotificationControllerV2Test {
assertEquals
(
watchKeysMap
.
size
(),
deferredResults
.
size
());
for
(
String
watchKey
:
watchKeysMap
.
values
())
{
assertTrue
(
deferredResults
.
get
(
watchKey
).
contains
(
deferredResult
));
}
assertWatchKeys
(
watchKeysMap
,
deferredResult
);
}
...
...
@@ -165,8 +165,8 @@ public class NotificationControllerV2Test {
String
somePublicNamespaceAsFile
=
somePublicNamespace
+
".xml"
;
when
(
namespaceUtil
.
filterNamespaceName
(
defaultNamespaceAsFile
)).
thenReturn
(
defaultNamespace
);
when
(
namespaceUtil
.
filterNamespaceName
(
somePublicNamespaceAsFile
))
.
thenReturn
(
somePublicNamespaceAsFile
);
when
(
namespaceUtil
.
filterNamespaceName
(
somePublicNamespaceAsFile
))
.
thenReturn
(
somePublicNamespaceAsFile
);
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
somePublicNamespaceAsFile
))
.
thenReturn
(
somePublicNamespaceAsFile
);
String
someWatchKey
=
"someKey"
;
String
anotherWatchKey
=
"anotherKey"
;
...
...
@@ -199,9 +199,7 @@ public class NotificationControllerV2Test {
assertEquals
(
watchKeysMap
.
size
(),
deferredResults
.
size
());
for
(
String
watchKey
:
watchKeysMap
.
values
())
{
assertTrue
(
deferredResults
.
get
(
watchKey
).
contains
(
deferredResult
));
}
assertWatchKeys
(
watchKeysMap
,
deferredResult
);
verify
(
watchKeysUtil
,
times
(
1
)).
assembleAllWatchKeys
(
someAppId
,
someCluster
,
Sets
.
newHashSet
(
defaultNamespace
,
somePublicNamespace
,
somePublicNamespaceAsFile
),
...
...
@@ -214,12 +212,15 @@ public class NotificationControllerV2Test {
String
someWatchKey
=
"someKey"
;
String
anotherWatchKey
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppId
,
someCluster
,
somePublicNamespace
);
String
yetAnotherWatchKey
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppId
,
defaultCluster
,
somePublicNamespace
);
long
notificationId
=
someNotificationId
+
1
;
long
yetAnotherNotificationId
=
someNotificationId
;
Multimap
<
String
,
String
>
watchKeysMap
=
assembleMultiMap
(
defaultNamespace
,
Lists
.
newArrayList
(
someWatchKey
));
watchKeysMap
.
putAll
(
assembleMultiMap
(
somePublicNamespace
,
Lists
.
newArrayList
(
anotherWatchKey
)));
.
putAll
(
assembleMultiMap
(
somePublicNamespace
,
Lists
.
newArrayList
(
anotherWatchKey
,
yetAnotherWatchKey
)));
when
(
watchKeysUtil
.
assembleAllWatchKeys
(
someAppId
,
someCluster
,
...
...
@@ -229,9 +230,12 @@ public class NotificationControllerV2Test {
ReleaseMessage
someReleaseMessage
=
mock
(
ReleaseMessage
.
class
);
when
(
someReleaseMessage
.
getId
()).
thenReturn
(
notificationId
);
when
(
someReleaseMessage
.
getMessage
()).
thenReturn
(
anotherWatchKey
);
ReleaseMessage
yetAnotherReleaseMessage
=
mock
(
ReleaseMessage
.
class
);
when
(
yetAnotherReleaseMessage
.
getId
()).
thenReturn
(
yetAnotherNotificationId
);
when
(
yetAnotherReleaseMessage
.
getMessage
()).
thenReturn
(
yetAnotherWatchKey
);
when
(
releaseMessageService
.
findLatestReleaseMessagesGroupByMessages
(
Sets
.
newHashSet
(
watchKeysMap
.
values
())))
.
thenReturn
(
Lists
.
newArrayList
(
someReleaseMessage
));
.
thenReturn
(
Lists
.
newArrayList
(
someReleaseMessage
,
yetAnotherReleaseMessage
));
String
notificationAsString
=
transformApolloConfigNotificationsToString
(
defaultNamespace
,
someNotificationId
,
...
...
@@ -249,6 +253,11 @@ public class NotificationControllerV2Test {
assertEquals
(
1
,
result
.
getBody
().
size
());
assertEquals
(
somePublicNamespace
,
result
.
getBody
().
get
(
0
).
getNamespaceName
());
assertEquals
(
notificationId
,
result
.
getBody
().
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
notificationMessages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
2
,
notificationMessages
.
getDetails
().
size
());
assertEquals
(
notificationId
,
notificationMessages
.
get
(
anotherWatchKey
).
longValue
());
assertEquals
(
yetAnotherNotificationId
,
notificationMessages
.
get
(
yetAnotherWatchKey
).
longValue
());
}
@Test
...
...
@@ -286,11 +295,16 @@ public class NotificationControllerV2Test {
ResponseEntity
<
List
<
ApolloConfigNotification
>>
response
=
(
ResponseEntity
<
List
<
ApolloConfigNotification
>>)
deferredResult
.
getResult
();
assertEquals
(
1
,
response
.
getBody
().
size
());
ApolloConfigNotification
notification
=
response
.
getBody
().
get
(
0
);
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertEquals
(
somePublicNamespace
,
notification
.
getNamespaceName
());
assertEquals
(
someId
,
notification
.
getNotificationId
());
ApolloNotificationMessages
notificationMessages
=
response
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
notificationMessages
.
getDetails
().
size
());
assertEquals
(
someId
,
notificationMessages
.
get
(
anotherWatchKey
).
longValue
());
}
@Test
...
...
@@ -365,9 +379,7 @@ public class NotificationControllerV2Test {
private
ApolloConfigNotification
assembleApolloConfigNotification
(
String
namespace
,
long
notificationId
)
{
ApolloConfigNotification
notification
=
new
ApolloConfigNotification
();
notification
.
setNamespaceName
(
namespace
);
notification
.
setNotificationId
(
notificationId
);
ApolloConfigNotification
notification
=
new
ApolloConfigNotification
(
namespace
,
notificationId
);
return
notification
;
}
...
...
@@ -376,4 +388,17 @@ public class NotificationControllerV2Test {
multimap
.
putAll
(
key
,
values
);
return
multimap
;
}
private
void
assertWatchKeys
(
Multimap
<
String
,
String
>
watchKeysMap
,
DeferredResult
deferredResult
)
{
for
(
String
watchKey
:
watchKeysMap
.
values
())
{
Collection
<
DeferredResultWrapper
>
deferredResultWrappers
=
deferredResults
.
get
(
watchKey
);
boolean
found
=
false
;
for
(
DeferredResultWrapper
wrapper:
deferredResultWrappers
)
{
if
(
Objects
.
equals
(
wrapper
.
getResult
(),
deferredResult
))
{
found
=
true
;
}
}
assertTrue
(
found
);
}
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/AbstractBaseIntegrationTest.java
浏览文件 @
2a834828
...
...
@@ -3,6 +3,7 @@ package com.ctrip.framework.apollo.configservice.integration;
import
com.google.gson.Gson
;
import
com.ctrip.framework.apollo.ConfigServiceTestConfiguration
;
import
com.ctrip.framework.apollo.biz.config.BizConfig
;
import
com.ctrip.framework.apollo.biz.entity.Namespace
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
...
...
@@ -16,6 +17,7 @@ import org.springframework.beans.factory.annotation.Value;
import
org.springframework.boot.test.SpringApplicationConfiguration
;
import
org.springframework.boot.test.TestRestTemplate
;
import
org.springframework.boot.test.WebIntegrationTest
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Import
;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
...
...
@@ -61,6 +63,10 @@ public abstract class AbstractBaseIntegrationTest {
@Configuration
@Import
(
ConfigServiceTestConfiguration
.
class
)
protected
static
class
TestConfiguration
{
@Bean
public
BizConfig
bizConfig
()
{
return
new
TestBizConfig
();
}
}
protected
void
sendReleaseMessage
(
String
message
)
{
...
...
@@ -105,4 +111,15 @@ public abstract class AbstractBaseIntegrationTest {
});
}
private
static
class
TestBizConfig
extends
BizConfig
{
@Override
public
int
appNamespaceCacheScanInterval
()
{
return
50
;
}
@Override
public
TimeUnit
appNamespaceCacheScanIntervalTimeUnit
()
{
return
TimeUnit
.
MILLISECONDS
;
}
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/ConfigControllerIntegrationTest.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.integration
;
import
com.ctrip.framework.apollo.configservice.service.AppNamespaceServiceWithCache
;
import
com.google.common.base.Joiner
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
...
...
@@ -7,9 +8,11 @@ import com.ctrip.framework.apollo.core.dto.ApolloConfig;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.test.context.jdbc.Sql
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
org.springframework.web.client.HttpStatusCodeException
;
import
java.util.concurrent.ExecutorService
;
...
...
@@ -33,8 +36,13 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
private
String
someClientIp
;
private
ExecutorService
executorService
;
@Autowired
private
AppNamespaceServiceWithCache
appNamespaceServiceWithCache
;
@Before
public
void
setUp
()
throws
Exception
{
ReflectionTestUtils
.
invokeMethod
(
appNamespaceServiceWithCache
,
"reset"
);
someAppId
=
"someAppId"
;
someCluster
=
"someCluster"
;
someNamespace
=
"someNamespace"
;
...
...
@@ -60,6 +68,21 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
assertEquals
(
"v1"
,
result
.
getConfigurations
().
get
(
"k1"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryConfigWithDefaultClusterAndDefaultNamespaceAndIncorrectCase
()
throws
Exception
{
ResponseEntity
<
ApolloConfig
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}"
,
ApolloConfig
.
class
,
getHostUrl
(),
someAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
ConfigConsts
.
NAMESPACE_APPLICATION
.
toUpperCase
());
ApolloConfig
result
=
response
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertEquals
(
"TEST-RELEASE-KEY1"
,
result
.
getReleaseKey
());
assertEquals
(
"v1"
,
result
.
getConfigurations
().
get
(
"k1"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-gray-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
...
...
@@ -83,6 +106,30 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
assertEquals
(
"v1-gray"
,
result
.
getConfigurations
().
get
(
"k1"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-gray-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryGrayConfigWithDefaultClusterAndDefaultNamespaceAndIncorrectCase
()
throws
Exception
{
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
someAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
ConfigConsts
.
NAMESPACE_APPLICATION
),
stop
);
TimeUnit
.
MILLISECONDS
.
sleep
(
500
);
stop
.
set
(
true
);
ResponseEntity
<
ApolloConfig
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?ip={clientIp}"
,
ApolloConfig
.
class
,
getHostUrl
(),
someAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
ConfigConsts
.
NAMESPACE_APPLICATION
.
toUpperCase
(),
someClientIp
);
ApolloConfig
result
=
response
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertEquals
(
"TEST-GRAY-RELEASE-KEY1"
,
result
.
getReleaseKey
());
assertEquals
(
"v1-gray"
,
result
.
getConfigurations
().
get
(
"k1"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
...
...
@@ -218,6 +265,24 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
assertEquals
(
"someDC-v2"
,
result
.
getConfigurations
().
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-public-dc-override.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryPublicConfigWithIncorrectCaseAndDataCenterFoundAndOverride
()
throws
Exception
{
ResponseEntity
<
ApolloConfig
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
ApolloConfig
.
class
,
getHostUrl
(),
someAppId
,
someDefaultCluster
,
somePublicNamespace
.
toUpperCase
(),
someDC
);
ApolloConfig
result
=
response
.
getBody
();
assertEquals
(
"TEST-RELEASE-KEY6"
+
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
+
"TEST-RELEASE-KEY4"
,
result
.
getReleaseKey
());
assertEquals
(
"override-someDC-v1"
,
result
.
getConfigurations
().
get
(
"k1"
));
assertEquals
(
"someDC-v2"
,
result
.
getConfigurations
().
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
...
...
@@ -286,6 +351,33 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
assertEquals
(
"gray-v2"
,
result
.
getConfigurations
().
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-public-default-override.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-gray-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryPublicGrayConfigWithIncorrectCaseAndOverride
()
throws
Exception
{
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
somePublicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
),
stop
);
TimeUnit
.
MILLISECONDS
.
sleep
(
500
);
stop
.
set
(
true
);
ResponseEntity
<
ApolloConfig
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?ip={clientIp}"
,
ApolloConfig
.
class
,
getHostUrl
(),
someAppId
,
someDefaultCluster
,
somePublicNamespace
.
toUpperCase
(),
someClientIp
);
ApolloConfig
result
=
response
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertEquals
(
"TEST-RELEASE-KEY5"
+
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
+
"TEST-GRAY-RELEASE-KEY2"
,
result
.
getReleaseKey
());
assertEquals
(
"override-v1"
,
result
.
getConfigurations
().
get
(
"k1"
));
assertEquals
(
"gray-v2"
,
result
.
getConfigurations
().
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/ConfigFileControllerIntegrationTest.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.integration
;
import
com.ctrip.framework.apollo.configservice.service.AppNamespaceServiceWithCache
;
import
com.google.common.base.Joiner
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
...
...
@@ -12,6 +13,7 @@ import com.netflix.servo.util.Strings;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.test.context.jdbc.Sql
;
...
...
@@ -23,6 +25,7 @@ import java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
...
...
@@ -45,8 +48,12 @@ public class ConfigFileControllerIntegrationTest extends AbstractBaseIntegration
private
ExecutorService
executorService
;
private
Type
mapResponseType
=
new
TypeToken
<
Map
<
String
,
String
>>(){}.
getType
();
@Autowired
private
AppNamespaceServiceWithCache
appNamespaceServiceWithCache
;
@Before
public
void
setUp
()
throws
Exception
{
ReflectionTestUtils
.
invokeMethod
(
appNamespaceServiceWithCache
,
"reset"
);
someDefaultCluster
=
ConfigConsts
.
CLUSTER_NAME_DEFAULT
;
someAppId
=
"someAppId"
;
somePublicAppId
=
"somePublicAppId"
;
...
...
@@ -142,6 +149,21 @@ public class ConfigFileControllerIntegrationTest extends AbstractBaseIntegration
assertEquals
(
"v2"
,
configs
.
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryConfigAsJsonWithIncorrectCase
()
throws
Exception
{
ResponseEntity
<
String
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}"
,
String
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
someNamespace
.
toUpperCase
());
Map
<
String
,
String
>
configs
=
gson
.
fromJson
(
response
.
getBody
(),
mapResponseType
);
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertEquals
(
"v2"
,
configs
.
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-public-dc-override.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
...
...
@@ -161,6 +183,25 @@ public class ConfigFileControllerIntegrationTest extends AbstractBaseIntegration
assertEquals
(
"someDC-v2"
,
configs
.
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-public-dc-override.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryPublicConfigAsJsonWithIncorrectCase
()
throws
Exception
{
ResponseEntity
<
String
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
String
.
class
,
getHostUrl
(),
someAppId
,
someDefaultCluster
,
somePublicNamespace
.
toUpperCase
(),
someDC
);
Map
<
String
,
String
>
configs
=
gson
.
fromJson
(
response
.
getBody
(),
mapResponseType
);
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertEquals
(
"override-someDC-v1"
,
configs
.
get
(
"k1"
));
assertEquals
(
"someDC-v2"
,
configs
.
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-public-default-override.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
...
...
@@ -202,6 +243,47 @@ public class ConfigFileControllerIntegrationTest extends AbstractBaseIntegration
assertEquals
(
"default-v2"
,
anotherConfigs
.
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-public-default-override.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-gray-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryPublicConfigAsJsonWithGrayReleaseAndIncorrectCase
()
throws
Exception
{
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
somePublicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
),
stop
);
TimeUnit
.
MILLISECONDS
.
sleep
(
500
);
stop
.
set
(
true
);
ResponseEntity
<
String
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}?ip={clientIp}"
,
String
.
class
,
getHostUrl
(),
someAppId
,
someDefaultCluster
,
somePublicNamespace
.
toUpperCase
(),
grayClientIp
);
ResponseEntity
<
String
>
anotherResponse
=
restTemplate
.
getForEntity
(
"{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}?ip={clientIp}"
,
String
.
class
,
getHostUrl
(),
someAppId
,
someDefaultCluster
,
somePublicNamespace
.
toUpperCase
(),
nonGrayClientIp
);
Map
<
String
,
String
>
configs
=
gson
.
fromJson
(
response
.
getBody
(),
mapResponseType
);
Map
<
String
,
String
>
anotherConfigs
=
gson
.
fromJson
(
anotherResponse
.
getBody
(),
mapResponseType
);
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertEquals
(
HttpStatus
.
OK
,
anotherResponse
.
getStatusCode
());
assertEquals
(
"override-v1"
,
configs
.
get
(
"k1"
));
assertEquals
(
"gray-v2"
,
configs
.
get
(
"k2"
));
assertEquals
(
"override-v1"
,
anotherConfigs
.
get
(
"k1"
));
assertEquals
(
"default-v2"
,
anotherConfigs
.
get
(
"k2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/NotificationControllerIntegrationTest.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.integration
;
import
com.ctrip.framework.apollo.configservice.service.AppNamespaceServiceWithCache
;
import
com.google.common.base.Joiner
;
import
com.ctrip.framework.apollo.configservice.service.ReleaseMessageServiceWithCache
;
...
...
@@ -35,10 +36,13 @@ public class NotificationControllerIntegrationTest extends AbstractBaseIntegrati
@Autowired
private
ReleaseMessageServiceWithCache
releaseMessageServiceWithCache
;
@Autowired
private
AppNamespaceServiceWithCache
appNamespaceServiceWithCache
;
@Before
public
void
setUp
()
throws
Exception
{
ReflectionTestUtils
.
invokeMethod
(
releaseMessageServiceWithCache
,
"reset"
);
ReflectionTestUtils
.
invokeMethod
(
appNamespaceServiceWithCache
,
"reset"
);
someAppId
=
"someAppId"
;
someCluster
=
ConfigConsts
.
CLUSTER_NAME_DEFAULT
;
defaultNamespace
=
ConfigConsts
.
NAMESPACE_APPLICATION
;
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/NotificationControllerV2IntegrationTest.java
浏览文件 @
2a834828
此差异已折叠。
点击以展开。
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/service/AppNamespaceServiceWithCacheTest.java
浏览文件 @
2a834828
...
...
@@ -23,6 +23,7 @@ import java.util.Set;
import
java.util.concurrent.TimeUnit
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNull
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
mockito
.
Mockito
.
when
;
...
...
@@ -62,6 +63,7 @@ public class AppNamespaceServiceWithCacheTest {
public
void
testAppNamespace
()
throws
Exception
{
String
someAppId
=
"someAppId"
;
String
somePrivateNamespace
=
"somePrivateNamespace"
;
String
somePrivateNamespaceWithIncorrectCase
=
somePrivateNamespace
.
toUpperCase
();
long
somePrivateNamespaceId
=
1
;
String
yetAnotherPrivateNamespace
=
"anotherPrivateNamespace"
;
long
yetAnotherPrivateNamespaceId
=
4
;
...
...
@@ -70,6 +72,7 @@ public class AppNamespaceServiceWithCacheTest {
String
somePublicAppId
=
"somePublicAppId"
;
String
somePublicNamespace
=
"somePublicNamespace"
;
String
somePublicNamespaceWithIncorrectCase
=
somePublicNamespace
.
toUpperCase
();
long
somePublicNamespaceId
=
2
;
String
anotherPrivateNamespace
=
"anotherPrivateNamespace"
;
long
anotherPrivateNamespaceId
=
3
;
...
...
@@ -89,9 +92,13 @@ public class AppNamespaceServiceWithCacheTest {
Set
<
String
>
someAppIdNamespaces
=
Sets
.
newHashSet
(
somePrivateNamespace
,
yetAnotherPrivateNamespace
,
anotherPublicNamespace
);
Set
<
String
>
someAppIdNamespacesWithIncorrectCase
=
Sets
.
newHashSet
(
somePrivateNamespaceWithIncorrectCase
,
yetAnotherPrivateNamespace
,
anotherPublicNamespace
);
Set
<
String
>
somePublicAppIdNamespaces
=
Sets
.
newHashSet
(
somePublicNamespace
,
anotherPrivateNamespace
);
Set
<
String
>
publicNamespaces
=
Sets
.
newHashSet
(
somePublicNamespace
,
anotherPublicNamespace
);
Set
<
String
>
publicNamespacesWithIncorrectCase
=
Sets
.
newHashSet
(
somePublicNamespaceWithIncorrectCase
,
anotherPublicNamespace
);
List
<
Long
>
appNamespaceIds
=
Lists
.
newArrayList
(
somePrivateNamespaceId
,
somePublicNamespaceId
,
anotherPrivateNamespaceId
,
yetAnotherPrivateNamespaceId
,
...
...
@@ -104,12 +111,24 @@ public class AppNamespaceServiceWithCacheTest {
appNamespaceServiceWithCache
.
afterPropertiesSet
();
// Should have no record now
assertTrue
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
someAppId
,
someAppIdNamespaces
)
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
somePrivateNamespace
));
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
somePrivateNamespaceWithIncorrectCase
));
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
yetAnotherPrivateNamespace
));
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
anotherPublicNamespace
));
assertTrue
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
someAppId
,
someAppIdNamespaces
).
isEmpty
());
assertTrue
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
someAppId
,
someAppIdNamespacesWithIncorrectCase
)
.
isEmpty
());
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
somePublicAppId
,
somePublicNamespace
));
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
somePublicAppId
,
somePublicNamespaceWithIncorrectCase
));
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
somePublicAppId
,
anotherPrivateNamespace
));
assertTrue
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
somePublicAppId
,
somePublicAppIdNamespaces
).
isEmpty
());
assertTrue
(
appNamespaceServiceWithCache
.
findPublicNamespacesByNames
(
publicNamespaces
).
isEmpty
());
assertNull
(
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
somePublicNamespace
));
assertNull
(
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
somePublicNamespaceWithIncorrectCase
));
assertNull
(
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
anotherPublicNamespace
));
assertTrue
(
appNamespaceServiceWithCache
.
findPublicNamespacesByNames
(
publicNamespaces
).
isEmpty
());
assertTrue
(
appNamespaceServiceWithCache
.
findPublicNamespacesByNames
(
publicNamespacesWithIncorrectCase
).
isEmpty
());
// Add 1 private namespace and 1 public namespace
when
(
appNamespaceRepository
.
findFirst500ByIdGreaterThanOrderByIdAsc
(
0
)).
thenReturn
(
Lists
...
...
@@ -120,12 +139,27 @@ public class AppNamespaceServiceWithCacheTest {
scanIntervalTimeUnit
.
sleep
(
sleepInterval
);
assertEquals
(
somePrivateAppNamespace
,
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
somePrivateNamespace
));
assertEquals
(
somePrivateAppNamespace
,
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
somePrivateNamespaceWithIncorrectCase
));
check
(
Lists
.
newArrayList
(
somePrivateAppNamespace
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
someAppId
,
someAppIdNamespaces
));
check
(
Lists
.
newArrayList
(
somePrivateAppNamespace
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
someAppId
,
someAppIdNamespacesWithIncorrectCase
));
assertEquals
(
somePublicAppNamespace
,
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
somePublicAppId
,
somePublicNamespace
));
assertEquals
(
somePublicAppNamespace
,
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
somePublicAppId
,
somePublicNamespaceWithIncorrectCase
));
check
(
Lists
.
newArrayList
(
somePublicAppNamespace
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
somePublicAppId
,
somePublicAppIdNamespaces
));
check
(
Lists
.
newArrayList
(
somePublicAppNamespace
),
appNamespaceServiceWithCache
.
findPublicNamespacesByNames
(
publicNamespaces
));
assertEquals
(
somePublicAppNamespace
,
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
somePublicNamespace
));
assertEquals
(
somePublicAppNamespace
,
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
somePublicNamespaceWithIncorrectCase
));
check
(
Lists
.
newArrayList
(
somePublicAppNamespace
),
appNamespaceServiceWithCache
.
findPublicNamespacesByNames
(
publicNamespaces
));
check
(
Lists
.
newArrayList
(
somePublicAppNamespace
),
appNamespaceServiceWithCache
.
findPublicNamespacesByNames
(
publicNamespacesWithIncorrectCase
));
// Add 2 private namespaces and 1 public namespace
when
(
appNamespaceRepository
.
findFirst500ByIdGreaterThanOrderByIdAsc
(
somePublicNamespaceId
))
...
...
@@ -135,12 +169,23 @@ public class AppNamespaceServiceWithCacheTest {
scanIntervalTimeUnit
.
sleep
(
sleepInterval
);
check
(
Lists
.
newArrayList
(
somePrivateAppNamespace
,
yetAnotherPrivateAppNamespace
,
anotherPublicAppNamespace
),
Lists
.
newArrayList
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
somePrivateNamespace
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
yetAnotherPrivateNamespace
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
anotherPublicNamespace
)));
check
(
Lists
.
newArrayList
(
somePrivateAppNamespace
,
yetAnotherPrivateAppNamespace
,
anotherPublicAppNamespace
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
someAppId
,
someAppIdNamespaces
));
check
(
Lists
.
newArrayList
(
somePublicAppNamespace
,
anotherPrivateAppNamespace
),
Lists
.
newArrayList
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
somePublicAppId
,
somePublicNamespace
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
somePublicAppId
,
anotherPrivateNamespace
)));
check
(
Lists
.
newArrayList
(
somePublicAppNamespace
,
anotherPrivateAppNamespace
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
somePublicAppId
,
somePublicAppIdNamespaces
));
check
(
Lists
.
newArrayList
(
somePublicAppNamespace
,
anotherPublicAppNamespace
),
Lists
.
newArrayList
(
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
somePublicNamespace
),
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
anotherPublicNamespace
)));
check
(
Lists
.
newArrayList
(
somePublicAppNamespace
,
anotherPublicAppNamespace
),
appNamespaceServiceWithCache
.
findPublicNamespacesByNames
(
publicNamespaces
));
...
...
@@ -173,16 +218,27 @@ public class AppNamespaceServiceWithCacheTest {
scanIntervalTimeUnit
.
sleep
(
sleepInterval
);
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
somePrivateNamespace
));
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
yetAnotherPrivateNamespace
));
assertNull
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
anotherPublicNamespace
));
check
(
Collections
.
emptyList
(),
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
someAppId
,
someAppIdNamespaces
));
assertEquals
(
somePublicAppNamespaceNew
,
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
somePublicAppId
,
somePublicNamespace
));
check
(
Lists
.
newArrayList
(
somePublicAppNamespaceNew
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
somePublicAppId
,
somePublicAppIdNamespaces
));
assertNull
(
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
somePublicNamespace
));
assertNull
(
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
anotherPublicNamespace
));
check
(
Collections
.
emptyList
(),
appNamespaceServiceWithCache
.
findPublicNamespacesByNames
(
publicNamespaces
));
assertEquals
(
somePrivateAppNamespaceNew
,
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
somePrivateNamespaceNew
));
check
(
Lists
.
newArrayList
(
somePrivateAppNamespaceNew
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
someAppId
,
Sets
.
newHashSet
(
somePrivateNamespaceNew
)));
assertEquals
(
yetAnotherPrivateAppNamespaceNew
,
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppIdNew
,
yetAnotherPrivateNamespace
));
check
(
Lists
.
newArrayList
(
yetAnotherPrivateAppNamespaceNew
),
appNamespaceServiceWithCache
.
findByAppIdAndNamespaces
(
someAppIdNew
,
Sets
.
newHashSet
(
yetAnotherPrivateNamespace
)));
}
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/service/config/ConfigServiceWithCacheTest.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.service.config
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.google.common.collect.Lists
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.framework.apollo.biz.message.Topics
;
import
com.ctrip.framework.apollo.biz.service.ReleaseMessageService
;
import
com.ctrip.framework.apollo.biz.service.ReleaseService
;
import
com.ctrip.framework.apollo.biz.utils.ReleaseMessageKeyGenerator
;
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
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNull
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
ConfigServiceWithCacheTest
{
private
ConfigServiceWithCache
configServiceWithCache
;
@Mock
private
ReleaseService
releaseService
;
@Mock
private
ReleaseMessageService
releaseMessageService
;
@Mock
private
Release
someRelease
;
@Mock
private
ReleaseMessage
someReleaseMessage
;
private
String
someAppId
;
private
String
someClusterName
;
private
String
someNamespaceName
;
private
String
someKey
;
private
long
someNotificationId
;
private
ApolloNotificationMessages
someNotificationMessages
;
@Before
public
void
setUp
()
throws
Exception
{
configServiceWithCache
=
new
ConfigServiceWithCache
();
ReflectionTestUtils
.
setField
(
configServiceWithCache
,
"releaseService"
,
releaseService
);
ReflectionTestUtils
.
setField
(
configServiceWithCache
,
"releaseMessageService"
,
releaseMessageService
);
configServiceWithCache
.
initialize
();
someAppId
=
"someAppId"
;
someClusterName
=
"someClusterName"
;
someNamespaceName
=
"someNamespaceName"
;
someNotificationId
=
1
;
someKey
=
ReleaseMessageKeyGenerator
.
generate
(
someAppId
,
someClusterName
,
someNamespaceName
);
someNotificationMessages
=
new
ApolloNotificationMessages
();
}
@Test
public
void
testFindActiveOne
()
throws
Exception
{
long
someId
=
1
;
when
(
releaseService
.
findActiveOne
(
someId
)).
thenReturn
(
someRelease
);
assertEquals
(
someRelease
,
configServiceWithCache
.
findActiveOne
(
someId
,
someNotificationMessages
));
verify
(
releaseService
,
times
(
1
)).
findActiveOne
(
someId
);
}
@Test
public
void
testFindActiveOneWithSameIdMultipleTimes
()
throws
Exception
{
long
someId
=
1
;
when
(
releaseService
.
findActiveOne
(
someId
)).
thenReturn
(
someRelease
);
assertEquals
(
someRelease
,
configServiceWithCache
.
findActiveOne
(
someId
,
someNotificationMessages
));
assertEquals
(
someRelease
,
configServiceWithCache
.
findActiveOne
(
someId
,
someNotificationMessages
));
assertEquals
(
someRelease
,
configServiceWithCache
.
findActiveOne
(
someId
,
someNotificationMessages
));
verify
(
releaseService
,
times
(
1
)).
findActiveOne
(
someId
);
}
@Test
public
void
testFindActiveOneWithMultipleIdMultipleTimes
()
throws
Exception
{
long
someId
=
1
;
long
anotherId
=
2
;
Release
anotherRelease
=
mock
(
Release
.
class
);
when
(
releaseService
.
findActiveOne
(
someId
)).
thenReturn
(
someRelease
);
when
(
releaseService
.
findActiveOne
(
anotherId
)).
thenReturn
(
anotherRelease
);
assertEquals
(
someRelease
,
configServiceWithCache
.
findActiveOne
(
someId
,
someNotificationMessages
));
assertEquals
(
someRelease
,
configServiceWithCache
.
findActiveOne
(
someId
,
someNotificationMessages
));
assertEquals
(
anotherRelease
,
configServiceWithCache
.
findActiveOne
(
anotherId
,
someNotificationMessages
));
assertEquals
(
anotherRelease
,
configServiceWithCache
.
findActiveOne
(
anotherId
,
someNotificationMessages
));
verify
(
releaseService
,
times
(
1
)).
findActiveOne
(
someId
);
verify
(
releaseService
,
times
(
1
)).
findActiveOne
(
anotherId
);
}
@Test
public
void
testFindActiveOneWithReleaseNotFoundMultipleTimes
()
throws
Exception
{
long
someId
=
1
;
when
(
releaseService
.
findActiveOne
(
someId
)).
thenReturn
(
null
);
assertNull
(
configServiceWithCache
.
findActiveOne
(
someId
,
someNotificationMessages
));
assertNull
(
configServiceWithCache
.
findActiveOne
(
someId
,
someNotificationMessages
));
assertNull
(
configServiceWithCache
.
findActiveOne
(
someId
,
someNotificationMessages
));
verify
(
releaseService
,
times
(
1
)).
findActiveOne
(
someId
);
}
@Test
public
void
testFindLatestActiveRelease
()
throws
Exception
{
when
(
releaseMessageService
.
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
))).
thenReturn
(
someReleaseMessage
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
someRelease
);
when
(
someReleaseMessage
.
getId
()).
thenReturn
(
someNotificationId
);
Release
release
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
Release
anotherRelease
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
int
retryTimes
=
100
;
for
(
int
i
=
0
;
i
<
retryTimes
;
i
++)
{
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
}
assertEquals
(
someRelease
,
release
);
assertEquals
(
someRelease
,
anotherRelease
);
verify
(
releaseMessageService
,
times
(
1
)).
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
));
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
);
}
@Test
public
void
testFindLatestActiveReleaseWithReleaseNotFound
()
throws
Exception
{
when
(
releaseMessageService
.
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
))).
thenReturn
(
null
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
null
);
Release
release
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
Release
anotherRelease
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
int
retryTimes
=
100
;
for
(
int
i
=
0
;
i
<
retryTimes
;
i
++)
{
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
}
assertNull
(
release
);
assertNull
(
anotherRelease
);
verify
(
releaseMessageService
,
times
(
1
)).
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
));
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
);
}
@Test
public
void
testFindLatestActiveReleaseWithDirtyRelease
()
throws
Exception
{
long
someNewNotificationId
=
someNotificationId
+
1
;
ReleaseMessage
anotherReleaseMessage
=
mock
(
ReleaseMessage
.
class
);
Release
anotherRelease
=
mock
(
Release
.
class
);
when
(
releaseMessageService
.
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
))).
thenReturn
(
someReleaseMessage
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
someRelease
);
when
(
someReleaseMessage
.
getId
()).
thenReturn
(
someNotificationId
);
Release
release
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
when
(
releaseMessageService
.
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
))).
thenReturn
(
anotherReleaseMessage
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
anotherRelease
);
when
(
anotherReleaseMessage
.
getId
()).
thenReturn
(
someNewNotificationId
);
Release
stillOldRelease
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
someNotificationMessages
.
put
(
someKey
,
someNewNotificationId
);
Release
shouldBeNewRelease
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
assertEquals
(
someRelease
,
release
);
assertEquals
(
someRelease
,
stillOldRelease
);
assertEquals
(
anotherRelease
,
shouldBeNewRelease
);
verify
(
releaseMessageService
,
times
(
2
)).
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
));
verify
(
releaseService
,
times
(
2
)).
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
);
}
@Test
public
void
testFindLatestActiveReleaseWithReleaseMessageNotification
()
throws
Exception
{
long
someNewNotificationId
=
someNotificationId
+
1
;
ReleaseMessage
anotherReleaseMessage
=
mock
(
ReleaseMessage
.
class
);
Release
anotherRelease
=
mock
(
Release
.
class
);
when
(
releaseMessageService
.
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
))).
thenReturn
(
someReleaseMessage
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
someRelease
);
when
(
someReleaseMessage
.
getId
()).
thenReturn
(
someNotificationId
);
Release
release
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
when
(
releaseMessageService
.
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
))).
thenReturn
(
anotherReleaseMessage
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
anotherRelease
);
when
(
anotherReleaseMessage
.
getMessage
()).
thenReturn
(
someKey
);
when
(
anotherReleaseMessage
.
getId
()).
thenReturn
(
someNewNotificationId
);
Release
stillOldRelease
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
configServiceWithCache
.
handleMessage
(
anotherReleaseMessage
,
Topics
.
APOLLO_RELEASE_TOPIC
);
Release
shouldBeNewRelease
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
assertEquals
(
someRelease
,
release
);
assertEquals
(
someRelease
,
stillOldRelease
);
assertEquals
(
anotherRelease
,
shouldBeNewRelease
);
verify
(
releaseMessageService
,
times
(
2
)).
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
));
verify
(
releaseService
,
times
(
2
)).
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
);
}
@Test
public
void
testFindLatestActiveReleaseWithIrrelevantMessages
()
throws
Exception
{
long
someNewNotificationId
=
someNotificationId
+
1
;
ReleaseMessage
anotherReleaseMessage
=
mock
(
ReleaseMessage
.
class
);
Release
anotherRelease
=
mock
(
Release
.
class
);
String
someIrrelevantKey
=
"someIrrelevantKey"
;
when
(
releaseMessageService
.
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
))).
thenReturn
(
someReleaseMessage
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
someRelease
);
when
(
someReleaseMessage
.
getId
()).
thenReturn
(
someNotificationId
);
Release
release
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
when
(
releaseMessageService
.
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
))).
thenReturn
(
anotherReleaseMessage
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
)).
thenReturn
(
anotherRelease
);
when
(
anotherReleaseMessage
.
getId
()).
thenReturn
(
someNewNotificationId
);
Release
stillOldRelease
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
someNotificationMessages
.
put
(
someIrrelevantKey
,
someNewNotificationId
);
Release
shouldStillBeOldRelease
=
configServiceWithCache
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
,
someNotificationMessages
);
assertEquals
(
someRelease
,
release
);
assertEquals
(
someRelease
,
stillOldRelease
);
assertEquals
(
someRelease
,
shouldStillBeOldRelease
);
verify
(
releaseMessageService
,
times
(
1
)).
findLatestReleaseMessageForMessages
(
Lists
.
newArrayList
(
someKey
));
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someNamespaceName
);
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/service/config/DefaultConfigServiceTest.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.service.config
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
mockito
.
Matchers
.
anyString
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
never
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.grayReleaseRule.GrayReleaseRulesHolder
;
import
com.ctrip.framework.apollo.biz.service.ReleaseService
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
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
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
DefaultConfigServiceTest
{
private
DefaultConfigService
configService
;
private
String
someClientAppId
;
private
String
someConfigAppId
;
private
String
someClusterName
;
private
String
defaultClusterName
;
private
String
defaultNamespaceName
;
private
String
someDataCenter
;
private
String
someClientIp
;
@Mock
private
ApolloNotificationMessages
someNotificationMessages
;
@Mock
private
ReleaseService
releaseService
;
@Mock
private
GrayReleaseRulesHolder
grayReleaseRulesHolder
;
@Mock
private
Release
someRelease
;
@Before
public
void
setUp
()
throws
Exception
{
configService
=
new
DefaultConfigService
();
ReflectionTestUtils
.
setField
(
configService
,
"releaseService"
,
releaseService
);
ReflectionTestUtils
.
setField
(
configService
,
"grayReleaseRulesHolder"
,
grayReleaseRulesHolder
);
someClientAppId
=
"1234"
;
someConfigAppId
=
"1"
;
someClusterName
=
"someClusterName"
;
defaultClusterName
=
ConfigConsts
.
CLUSTER_NAME_DEFAULT
;
defaultNamespaceName
=
ConfigConsts
.
NAMESPACE_APPLICATION
;
someDataCenter
=
"someDC"
;
someClientIp
=
"someClientIp"
;
when
(
grayReleaseRulesHolder
.
findReleaseIdFromGrayReleaseRule
(
anyString
(),
anyString
(),
anyString
(),
anyString
(),
anyString
())).
thenReturn
(
null
);
}
@Test
public
void
testLoadConfig
()
throws
Exception
{
when
(
releaseService
.
findLatestActiveRelease
(
someConfigAppId
,
someClusterName
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
Release
release
=
configService
.
loadConfig
(
someClientAppId
,
someClientIp
,
someConfigAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
);
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someConfigAppId
,
someClusterName
,
defaultNamespaceName
);
assertEquals
(
someRelease
,
release
);
}
@Test
public
void
testLoadConfigWithGrayRelease
()
throws
Exception
{
Release
grayRelease
=
mock
(
Release
.
class
);
long
grayReleaseId
=
999
;
when
(
grayReleaseRulesHolder
.
findReleaseIdFromGrayReleaseRule
(
someClientAppId
,
someClientIp
,
someConfigAppId
,
someClusterName
,
defaultNamespaceName
)).
thenReturn
(
grayReleaseId
);
when
(
releaseService
.
findActiveOne
(
grayReleaseId
)).
thenReturn
(
grayRelease
);
when
(
releaseService
.
findLatestActiveRelease
(
someConfigAppId
,
someClusterName
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
Release
release
=
configService
.
loadConfig
(
someClientAppId
,
someClientIp
,
someConfigAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
);
verify
(
releaseService
,
times
(
1
)).
findActiveOne
(
grayReleaseId
);
verify
(
releaseService
,
never
()).
findLatestActiveRelease
(
someConfigAppId
,
someClusterName
,
defaultNamespaceName
);
assertEquals
(
grayRelease
,
release
);
}
@Test
public
void
testLoadConfigWithReleaseNotFound
()
throws
Exception
{
when
(
releaseService
.
findLatestActiveRelease
(
someConfigAppId
,
someClusterName
,
defaultNamespaceName
))
.
thenReturn
(
null
);
Release
release
=
configService
.
loadConfig
(
someClientAppId
,
someClientIp
,
someConfigAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
);
assertNull
(
release
);
}
@Test
public
void
testLoadConfigWithDefaultClusterWithDataCenterRelease
()
throws
Exception
{
when
(
releaseService
.
findLatestActiveRelease
(
someConfigAppId
,
someDataCenter
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
Release
release
=
configService
.
loadConfig
(
someClientAppId
,
someClientIp
,
someConfigAppId
,
defaultClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
);
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someConfigAppId
,
someDataCenter
,
defaultNamespaceName
);
assertEquals
(
someRelease
,
release
);
}
@Test
public
void
testLoadConfigWithDefaultClusterWithNoDataCenterRelease
()
throws
Exception
{
when
(
releaseService
.
findLatestActiveRelease
(
someConfigAppId
,
someDataCenter
,
defaultNamespaceName
))
.
thenReturn
(
null
);
when
(
releaseService
.
findLatestActiveRelease
(
someConfigAppId
,
defaultClusterName
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
Release
release
=
configService
.
loadConfig
(
someClientAppId
,
someClientIp
,
someConfigAppId
,
defaultClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
);
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someConfigAppId
,
someDataCenter
,
defaultNamespaceName
);
verify
(
releaseService
,
times
(
1
))
.
findLatestActiveRelease
(
someConfigAppId
,
defaultClusterName
,
defaultNamespaceName
);
assertEquals
(
someRelease
,
release
);
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/util/NamespaceUtilTest.java
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.util
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
import
com.ctrip.framework.apollo.configservice.service.AppNamespaceServiceWithCache
;
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
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
never
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
NamespaceUtilTest
{
private
NamespaceUtil
namespaceUtil
;
@Mock
private
AppNamespaceServiceWithCache
appNamespaceServiceWithCache
;
@Before
public
void
setUp
()
throws
Exception
{
namespaceUtil
=
new
NamespaceUtil
();
ReflectionTestUtils
.
setField
(
namespaceUtil
,
"appNamespaceServiceWithCache"
,
appNamespaceServiceWithCache
);
}
@Test
...
...
@@ -50,4 +67,52 @@ public class NamespaceUtilTest {
assertEquals
(
someName
,
namespaceUtil
.
filterNamespaceName
(
someName
));
}
@Test
public
void
testNormalizeNamespaceWithPrivateNamespace
()
throws
Exception
{
String
someAppId
=
"someAppId"
;
String
someNamespaceName
=
"someNamespaceName"
;
String
someNormalizedNamespaceName
=
"someNormalizedNamespaceName"
;
AppNamespace
someAppNamespace
=
mock
(
AppNamespace
.
class
);
when
(
someAppNamespace
.
getName
()).
thenReturn
(
someNormalizedNamespaceName
);
when
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
someNamespaceName
)).
thenReturn
(
someAppNamespace
);
assertEquals
(
someNormalizedNamespaceName
,
namespaceUtil
.
normalizeNamespace
(
someAppId
,
someNamespaceName
));
verify
(
appNamespaceServiceWithCache
,
times
(
1
)).
findByAppIdAndNamespace
(
someAppId
,
someNamespaceName
);
verify
(
appNamespaceServiceWithCache
,
never
()).
findPublicNamespaceByName
(
someNamespaceName
);
}
@Test
public
void
testNormalizeNamespaceWithPublicNamespace
()
throws
Exception
{
String
someAppId
=
"someAppId"
;
String
someNamespaceName
=
"someNamespaceName"
;
String
someNormalizedNamespaceName
=
"someNormalizedNamespaceName"
;
AppNamespace
someAppNamespace
=
mock
(
AppNamespace
.
class
);
when
(
someAppNamespace
.
getName
()).
thenReturn
(
someNormalizedNamespaceName
);
when
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
someNamespaceName
)).
thenReturn
(
null
);
when
(
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
someNamespaceName
)).
thenReturn
(
someAppNamespace
);
assertEquals
(
someNormalizedNamespaceName
,
namespaceUtil
.
normalizeNamespace
(
someAppId
,
someNamespaceName
));
verify
(
appNamespaceServiceWithCache
,
times
(
1
)).
findByAppIdAndNamespace
(
someAppId
,
someNamespaceName
);
verify
(
appNamespaceServiceWithCache
,
times
(
1
)).
findPublicNamespaceByName
(
someNamespaceName
);
}
@Test
public
void
testNormalizeNamespaceFailed
()
throws
Exception
{
String
someAppId
=
"someAppId"
;
String
someNamespaceName
=
"someNamespaceName"
;
when
(
appNamespaceServiceWithCache
.
findByAppIdAndNamespace
(
someAppId
,
someNamespaceName
)).
thenReturn
(
null
);
when
(
appNamespaceServiceWithCache
.
findPublicNamespaceByName
(
someNamespaceName
)).
thenReturn
(
null
);
assertEquals
(
someNamespaceName
,
namespaceUtil
.
normalizeNamespace
(
someAppId
,
someNamespaceName
));
verify
(
appNamespaceServiceWithCache
,
times
(
1
)).
findByAppIdAndNamespace
(
someAppId
,
someNamespaceName
);
verify
(
appNamespaceServiceWithCache
,
times
(
1
)).
findPublicNamespaceByName
(
someNamespaceName
);
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/wrapper/CaseInsensitiveMapWrapperTest.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.configservice.wrapper
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.Mock
;
import
org.mockito.runners.MockitoJUnitRunner
;
import
java.util.Map
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
@author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
CaseInsensitiveMapWrapperTest
{
private
CaseInsensitiveMapWrapper
<
Object
>
caseInsensitiveMapWrapper
;
@Mock
private
Map
<
String
,
Object
>
someMap
;
@Before
public
void
setUp
()
throws
Exception
{
caseInsensitiveMapWrapper
=
new
CaseInsensitiveMapWrapper
<>(
someMap
);
}
@Test
public
void
testGet
()
throws
Exception
{
String
someKey
=
"someKey"
;
Object
someValue
=
mock
(
Object
.
class
);
when
(
someMap
.
get
(
someKey
.
toLowerCase
())).
thenReturn
(
someValue
);
assertEquals
(
someValue
,
caseInsensitiveMapWrapper
.
get
(
someKey
));
verify
(
someMap
,
times
(
1
)).
get
(
someKey
.
toLowerCase
());
}
@Test
public
void
testPut
()
throws
Exception
{
String
someKey
=
"someKey"
;
Object
someValue
=
mock
(
Object
.
class
);
Object
anotherValue
=
mock
(
Object
.
class
);
when
(
someMap
.
put
(
someKey
.
toLowerCase
(),
someValue
)).
thenReturn
(
anotherValue
);
assertEquals
(
anotherValue
,
caseInsensitiveMapWrapper
.
put
(
someKey
,
someValue
));
verify
(
someMap
,
times
(
1
)).
put
(
someKey
.
toLowerCase
(),
someValue
);
}
@Test
public
void
testRemove
()
throws
Exception
{
String
someKey
=
"someKey"
;
Object
someValue
=
mock
(
Object
.
class
);
when
(
someMap
.
remove
(
someKey
.
toLowerCase
())).
thenReturn
(
someValue
);
assertEquals
(
someValue
,
caseInsensitiveMapWrapper
.
remove
(
someKey
));
verify
(
someMap
,
times
(
1
)).
remove
(
someKey
.
toLowerCase
());
}
}
\ No newline at end of file
apollo-core/src/main/java/com/ctrip/framework/apollo/core/ConfigConsts.java
浏览文件 @
2a834828
...
...
@@ -7,4 +7,5 @@ public interface ConfigConsts {
String
APOLLO_CLUSTER_KEY
=
"apollo.cluster"
;
String
CONFIG_FILE_CONTENT_KEY
=
"content"
;
String
NO_APPID_PLACEHOLDER
=
"ApolloNoAppIdPlaceHolder"
;
long
NOTIFICATION_ID_PLACEHOLDER
=
-
1
;
}
apollo-core/src/main/java/com/ctrip/framework/apollo/core/dto/ApolloConfigNotification.java
浏览文件 @
2a834828
...
...
@@ -6,6 +6,7 @@ package com.ctrip.framework.apollo.core.dto;
public
class
ApolloConfigNotification
{
private
String
namespaceName
;
private
long
notificationId
;
private
volatile
ApolloNotificationMessages
messages
;
//for json converter
public
ApolloConfigNotification
()
{
...
...
@@ -28,8 +29,23 @@ public class ApolloConfigNotification {
this
.
namespaceName
=
namespaceName
;
}
public
void
setNotificationId
(
long
notificationId
)
{
this
.
notificationId
=
notificationId
;
public
ApolloNotificationMessages
getMessages
()
{
return
messages
;
}
public
void
setMessages
(
ApolloNotificationMessages
messages
)
{
this
.
messages
=
messages
;
}
public
void
addMessage
(
String
key
,
long
notificationId
)
{
if
(
this
.
messages
==
null
)
{
synchronized
(
this
)
{
if
(
this
.
messages
==
null
)
{
this
.
messages
=
new
ApolloNotificationMessages
();
}
}
}
this
.
messages
.
put
(
key
,
notificationId
);
}
@Override
...
...
apollo-core/src/main/java/com/ctrip/framework/apollo/core/dto/ApolloNotificationMessages.java
0 → 100644
浏览文件 @
2a834828
package
com.ctrip.framework.apollo.core.dto
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Maps
;
import
java.util.Map
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
ApolloNotificationMessages
{
private
Map
<
String
,
Long
>
details
;
public
ApolloNotificationMessages
()
{
this
(
Maps
.<
String
,
Long
>
newHashMap
());
}
private
ApolloNotificationMessages
(
Map
<
String
,
Long
>
details
)
{
this
.
details
=
details
;
}
public
void
put
(
String
key
,
long
notificationId
)
{
details
.
put
(
key
,
notificationId
);
}
public
Long
get
(
String
key
)
{
return
this
.
details
.
get
(
key
);
}
public
boolean
has
(
String
key
)
{
return
this
.
details
.
containsKey
(
key
);
}
public
boolean
isEmpty
()
{
return
this
.
details
.
isEmpty
();
}
public
Map
<
String
,
Long
>
getDetails
()
{
return
details
;
}
public
void
setDetails
(
Map
<
String
,
Long
>
details
)
{
this
.
details
=
details
;
}
public
void
mergeFrom
(
ApolloNotificationMessages
source
)
{
if
(
source
==
null
)
{
return
;
}
for
(
Map
.
Entry
<
String
,
Long
>
entry
:
source
.
getDetails
().
entrySet
())
{
//to make sure the notification id always grows bigger
if
(
this
.
has
(
entry
.
getKey
())
&&
this
.
get
(
entry
.
getKey
())
>=
entry
.
getValue
())
{
continue
;
}
this
.
put
(
entry
.
getKey
(),
entry
.
getValue
());
}
}
public
ApolloNotificationMessages
clone
()
{
return
new
ApolloNotificationMessages
(
ImmutableMap
.
copyOf
(
this
.
details
));
}
}
scripts/sql-docker/apolloconfigdb.sql
浏览文件 @
2a834828
...
...
@@ -367,7 +367,7 @@ VALUES
(
'eureka.service.url'
,
'default'
,
'http://apollo-configservice:8080/eureka/'
,
'Eureka服务Url,多个service以英文逗号分隔'
),
(
'namespace.lock.switch'
,
'default'
,
'false'
,
'一次发布只能有一个人修改开关'
),
(
'item.value.length.limit'
,
'default'
,
'20000'
,
'item value最大长度限制'
),
(
'
appnamespace.private.enable'
,
'default'
,
'false'
,
'是否开启private namespace
'
),
(
'
config-service.cache.enabled'
,
'default'
,
'false'
,
'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!
'
),
(
'item.key.length.limit'
,
'default'
,
'128'
,
'item key 最大长度限制'
);
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */
;
...
...
scripts/sql/apolloconfigdb.sql
浏览文件 @
2a834828
...
...
@@ -367,7 +367,7 @@ VALUES
(
'eureka.service.url'
,
'default'
,
'http://localhost:8080/eureka/'
,
'Eureka服务Url,多个service以英文逗号分隔'
),
(
'namespace.lock.switch'
,
'default'
,
'false'
,
'一次发布只能有一个人修改开关'
),
(
'item.value.length.limit'
,
'default'
,
'20000'
,
'item value最大长度限制'
),
(
'
appnamespace.private.enable'
,
'default'
,
'false'
,
'是否开启private namespace
'
),
(
'
config-service.cache.enabled'
,
'default'
,
'false'
,
'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!
'
),
(
'item.key.length.limit'
,
'default'
,
'128'
,
'item key 最大长度限制'
);
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录