Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
apollo
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
apollo
Commits
2a834828
Commit
2a834828
authored
Aug 27, 2017
by
张乐
Committed by
GitHub
Aug 27, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #719 from nobodyiam/configservice-cache-merge
Config service cache and namespace name normalization
parents
f68cb458
699009f8
Changes
44
Hide whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
2363 additions
and
500 deletions
+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
No files found.
apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/NamespaceBranchController.java
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
2a834828
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
controller
;
import
com.ctrip.framework.apollo.configservice.service.AppNamespaceServiceWithCache
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.google.common.base.Joiner
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
...
...
@@ -7,10 +9,8 @@ import com.google.gson.Gson;
import
com.google.gson.JsonSyntaxException
;
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.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
;
...
...
@@ -34,6 +34,7 @@ import static org.mockito.Matchers.anyString;
import
static
org
.
mockito
.
Matchers
.
eq
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
never
;
import
static
org
.
mockito
.
Mockito
.
spy
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
...
...
@@ -45,9 +46,9 @@ import static org.mockito.Mockito.when;
public
class
ConfigControllerTest
{
private
ConfigController
configController
;
@Mock
private
ReleaseService
release
Service
;
private
ConfigService
config
Service
;
@Mock
private
AppNamespaceService
appNamespaceService
;
private
AppNamespaceService
WithCache
appNamespaceService
;
private
String
someAppId
;
private
String
someClusterName
;
private
String
defaultClusterName
;
...
...
@@ -55,6 +56,9 @@ public class ConfigControllerTest {
private
String
somePublicNamespaceName
;
private
String
someDataCenter
;
private
String
someClientIp
;
private
String
someMessagesAsString
;
@Mock
private
ApolloNotificationMessages
someNotificationMessages
;
@Mock
private
Release
someRelease
;
@Mock
...
...
@@ -64,18 +68,17 @@ public class ConfigControllerTest {
@Mock
private
InstanceConfigAuditUtil
instanceConfigAuditUtil
;
@Mock
private
GrayReleaseRulesHolder
grayReleaseRulesHolder
;
@Mock
private
HttpServletRequest
someRequest
;
private
Gson
gson
=
new
Gson
();
@Before
public
void
setUp
()
throws
Exception
{
configController
=
new
ConfigController
(
);
ReflectionTestUtils
.
setField
(
configController
,
"
releaseService"
,
release
Service
);
configController
=
spy
(
new
ConfigController
()
);
ReflectionTestUtils
.
setField
(
configController
,
"
configService"
,
config
Service
);
ReflectionTestUtils
.
setField
(
configController
,
"appNamespaceService"
,
appNamespaceService
);
ReflectionTestUtils
.
setField
(
configController
,
"namespaceUtil"
,
namespaceUtil
);
ReflectionTestUtils
.
setField
(
configController
,
"instanceConfigAuditUtil"
,
instanceConfigAuditUtil
);
ReflectionTestUtils
.
setField
(
configController
,
"g
rayReleaseRulesHolder"
,
grayReleaseRulesHolder
);
ReflectionTestUtils
.
setField
(
configController
,
"g
son"
,
gson
);
someAppId
=
"1"
;
someClusterName
=
"someClusterName"
;
...
...
@@ -92,10 +95,12 @@ public class ConfigControllerTest {
when
(
someRelease
.
getConfigurations
()).
thenReturn
(
someValidConfiguration
);
when
(
somePublicRelease
.
getConfigurations
()).
thenReturn
(
somePublicConfiguration
);
when
(
namespaceUtil
.
filterNamespaceName
(
defaultNamespaceName
)).
thenReturn
(
defaultNamespaceName
);
when
(
namespaceUtil
.
filterNamespaceName
(
somePublicNamespaceName
))
.
thenReturn
(
somePublicNamespaceName
);
when
(
grayReleaseRulesHolder
.
findReleaseIdFromGrayReleaseRule
(
anyString
(),
anyString
(),
anyString
(),
anyString
(),
anyString
())).
thenReturn
(
null
);
when
(
namespaceUtil
.
filterNamespaceName
(
somePublicNamespaceName
)).
thenReturn
(
somePublicNamespaceName
);
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
defaultNamespaceName
)).
thenReturn
(
defaultNamespaceName
);
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
somePublicNamespaceName
)).
thenReturn
(
somePublicNamespaceName
);
someMessagesAsString
=
"someValidJson"
;
when
(
configController
.
transformMessages
(
someMessagesAsString
)).
thenReturn
(
someNotificationMessages
);
}
@Test
...
...
@@ -104,16 +109,17 @@ public class ConfigControllerTest {
String
someServerSideNewReleaseKey
=
"2"
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideNewReleaseKey
);
when
(
someRelease
.
getNamespaceName
()).
thenReturn
(
defaultNamespaceName
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someAppId
,
someClusterName
,
defaultNamespaceName
);
verify
(
configService
,
times
(
1
)).
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
);
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someClusterName
,
result
.
getCluster
());
assertEquals
(
defaultNamespaceName
,
result
.
getNamespaceName
());
...
...
@@ -122,45 +128,6 @@ public class ConfigControllerTest {
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
,
someServerSideNewReleaseKey
);
}
@Test
public
void
testQueryConfigWithGrayRelease
()
throws
Exception
{
String
someClientSideReleaseKey
=
"1"
;
String
someServerSideNewReleaseKey
=
"2"
;
String
someServerSideGrayReleaseKey
=
"3"
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
Release
grayRelease
=
mock
(
Release
.
class
);
long
grayReleaseId
=
999
;
String
someGrayConfiguration
=
"{\"apollo.bar\": \"foo_gray\"}"
;
when
(
grayReleaseRulesHolder
.
findReleaseIdFromGrayReleaseRule
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
)).
thenReturn
(
grayReleaseId
);
when
(
releaseService
.
findActiveOne
(
grayReleaseId
)).
thenReturn
(
grayRelease
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideNewReleaseKey
);
when
(
grayRelease
.
getAppId
()).
thenReturn
(
someAppId
);
when
(
grayRelease
.
getClusterName
()).
thenReturn
(
someClusterName
);
when
(
grayRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideGrayReleaseKey
);
when
(
grayRelease
.
getNamespaceName
()).
thenReturn
(
defaultNamespaceName
);
when
(
grayRelease
.
getConfigurations
()).
thenReturn
(
someGrayConfiguration
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
verify
(
releaseService
,
times
(
1
)).
findActiveOne
(
grayReleaseId
);
verify
(
releaseService
,
never
()).
findLatestActiveRelease
(
someAppId
,
someClusterName
,
defaultNamespaceName
);
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someClusterName
,
result
.
getCluster
());
assertEquals
(
defaultNamespaceName
,
result
.
getNamespaceName
());
assertEquals
(
someServerSideGrayReleaseKey
,
result
.
getReleaseKey
());
verify
(
instanceConfigAuditUtil
,
times
(
1
)).
audit
(
someAppId
,
someClusterName
,
someDataCenter
,
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
,
someServerSideGrayReleaseKey
);
}
@Test
public
void
testQueryConfigFile
()
throws
Exception
{
String
someClientSideReleaseKey
=
"1"
;
...
...
@@ -168,16 +135,18 @@ public class ConfigControllerTest {
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
String
someNamespaceName
=
String
.
format
(
"%s.%s"
,
defaultClusterName
,
"properties"
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideNewReleaseKey
);
when
(
namespaceUtil
.
filterNamespaceName
(
someNamespaceName
)).
thenReturn
(
defaultNamespaceName
);
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
someNamespaceName
)).
thenReturn
(
defaultNamespaceName
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someAppId
,
someClusterName
,
defaultNamespaceName
);
verify
(
configService
,
times
(
1
)).
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
);
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someClusterName
,
result
.
getCluster
());
assertEquals
(
someNamespaceName
,
result
.
getNamespaceName
());
...
...
@@ -193,16 +162,17 @@ public class ConfigControllerTest {
String
somePrivateNamespaceName
=
String
.
format
(
"%s.%s"
,
somePrivateNamespace
,
"xml"
);
AppNamespace
appNamespace
=
mock
(
AppNamespace
.
class
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
somePrivateNamespace
))
.
thenReturn
(
someRelease
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
somePrivateNamespace
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideNewReleaseKey
);
when
(
namespaceUtil
.
filterNamespaceName
(
somePrivateNamespaceName
)).
thenReturn
(
somePrivateNamespace
);
when
(
appNamespaceService
.
findOne
(
someAppId
,
somePrivateNamespace
))
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
somePrivateNamespace
)).
thenReturn
(
somePrivateNamespace
);
when
(
appNamespaceService
.
findByAppIdAndNamespace
(
someAppId
,
somePrivateNamespace
))
.
thenReturn
(
appNamespace
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
somePrivateNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someClusterName
,
result
.
getCluster
());
...
...
@@ -215,12 +185,12 @@ public class ConfigControllerTest {
String
someClientSideReleaseKey
=
"1"
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
defaultNamespaceName
))
.
thenReturn
(
null
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
null
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
assertNull
(
result
);
verify
(
someResponse
,
times
(
1
)).
sendError
(
eq
(
HttpServletResponse
.
SC_NOT_FOUND
),
anyString
());
...
...
@@ -232,67 +202,18 @@ public class ConfigControllerTest {
String
someServerSideReleaseKey
=
someClientSideReleaseKey
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideReleaseKey
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
String
.
valueOf
(
someClientSideReleaseKey
),
someClientIp
,
someRequest
,
someResponse
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
String
.
valueOf
(
someClientSideReleaseKey
),
someClientIp
,
someMessagesAsString
,
someRequest
,
someResponse
);
assertNull
(
result
);
verify
(
someResponse
,
times
(
1
)).
setStatus
(
HttpServletResponse
.
SC_NOT_MODIFIED
);
}
@Test
public
void
testQueryConfigWithDefaultClusterWithDataCenterRelease
()
throws
Exception
{
String
someClientSideReleaseKey
=
"1"
;
String
someServerSideNewReleaseKey
=
"2"
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someDataCenter
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideNewReleaseKey
);
when
(
someRelease
.
getClusterName
()).
thenReturn
(
someDataCenter
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
defaultClusterName
,
defaultNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someAppId
,
someDataCenter
,
defaultNamespaceName
);
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someDataCenter
,
result
.
getCluster
());
assertEquals
(
defaultNamespaceName
,
result
.
getNamespaceName
());
assertEquals
(
someServerSideNewReleaseKey
,
result
.
getReleaseKey
());
}
@Test
public
void
testQueryConfigWithDefaultClusterWithNoDataCenterRelease
()
throws
Exception
{
String
someClientSideReleaseKey
=
"1"
;
String
someServerSideNewReleaseKey
=
"2"
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someDataCenter
,
defaultNamespaceName
))
.
thenReturn
(
null
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
defaultClusterName
,
defaultNamespaceName
))
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideNewReleaseKey
);
when
(
someRelease
.
getClusterName
()).
thenReturn
(
defaultClusterName
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
defaultClusterName
,
defaultNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
verify
(
releaseService
,
times
(
1
)).
findLatestActiveRelease
(
someAppId
,
someDataCenter
,
defaultNamespaceName
);
verify
(
releaseService
,
times
(
1
))
.
findLatestActiveRelease
(
someAppId
,
defaultClusterName
,
defaultNamespaceName
);
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
defaultClusterName
,
result
.
getCluster
());
assertEquals
(
defaultNamespaceName
,
result
.
getNamespaceName
());
assertEquals
(
someServerSideNewReleaseKey
,
result
.
getReleaseKey
());
}
@Test
public
void
testQueryConfigWithAppOwnNamespace
()
throws
Exception
{
String
someClientSideReleaseKey
=
"1"
;
...
...
@@ -302,18 +223,18 @@ public class ConfigControllerTest {
AppNamespace
someAppOwnNamespace
=
assemblePublicAppNamespace
(
someAppId
,
someAppOwnNamespaceName
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
someAppOwnNamespaceName
))
.
thenReturn
(
someRelease
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
someAppOwnNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
someRelease
);
when
(
appNamespaceService
.
findPublicNamespaceByName
(
someAppOwnNamespaceName
))
.
thenReturn
(
someAppOwnNamespace
);
when
(
someRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideReleaseKey
);
when
(
namespaceUtil
.
filterNamespaceName
(
someAppOwnNamespaceName
))
.
thenReturn
(
someAppOwnNamespaceName
);
when
(
namespaceUtil
.
filterNamespaceName
(
someAppOwnNamespaceName
))
.
thenReturn
(
someAppOwnNamespaceName
);
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
someAppOwnNamespaceName
))
.
thenReturn
(
someAppOwnNamespaceName
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someAppOwnNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someClientSideReleaseKey
,
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
assertEquals
(
someServerSideReleaseKey
,
result
.
getReleaseKey
());
assertEquals
(
someAppId
,
result
.
getAppId
());
...
...
@@ -332,12 +253,12 @@ public class ConfigControllerTest {
AppNamespace
somePublicAppNamespace
=
assemblePublicAppNamespace
(
somePublicAppId
,
somePublicNamespaceName
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
somePublicNamespaceName
))
.
thenReturn
(
null
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
null
);
when
(
appNamespaceService
.
findPublicNamespaceByName
(
somePublicNamespaceName
))
.
thenReturn
(
somePublicAppNamespace
);
when
(
releaseService
.
findLatestActiveRelease
(
somePublicAppId
,
someDataCenter
,
somePublicNamespaceName
))
.
thenReturn
(
somePublicRelease
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
somePublicAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
somePublicRelease
);
when
(
somePublicRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideReleaseKey
);
when
(
somePublicRelease
.
getAppId
()).
thenReturn
(
somePublicAppId
);
when
(
somePublicRelease
.
getClusterName
()).
thenReturn
(
somePublicClusterName
);
...
...
@@ -345,7 +266,7 @@ public class ConfigControllerTest {
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someClientSideReleaseKey
,
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
assertEquals
(
someServerSideReleaseKey
,
result
.
getReleaseKey
());
assertEquals
(
someAppId
,
result
.
getAppId
());
...
...
@@ -366,19 +287,20 @@ public class ConfigControllerTest {
AppNamespace
somePublicAppNamespace
=
assemblePublicAppNamespace
(
somePublicAppId
,
somePublicNamespaceName
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
somePublicNamespaceName
))
.
thenReturn
(
null
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
null
);
when
(
appNamespaceService
.
findPublicNamespaceByName
(
somePublicNamespaceName
))
.
thenReturn
(
somePublicAppNamespace
);
when
(
releaseService
.
findLatestActiveRelease
(
somePublicAppId
,
someDataCenter
,
somePublicNamespaceName
))
.
thenReturn
(
somePublicRelease
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
somePublicAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
somePublicRelease
);
when
(
somePublicRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideReleaseKey
);
when
(
namespaceUtil
.
filterNamespaceName
(
someNamespace
)).
thenReturn
(
somePublicNamespaceName
);
when
(
appNamespaceService
.
findOne
(
someAppId
,
somePublicNamespaceName
)).
thenReturn
(
null
);
when
(
namespaceUtil
.
normalizeNamespace
(
someAppId
,
someNamespace
)).
thenReturn
(
somePublicNamespaceName
);
when
(
appNamespaceService
.
findByAppIdAndNamespace
(
someAppId
,
somePublicNamespaceName
)).
thenReturn
(
null
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someClientSideReleaseKey
,
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
assertEquals
(
someServerSideReleaseKey
,
result
.
getReleaseKey
());
assertEquals
(
someAppId
,
result
.
getAppId
());
...
...
@@ -387,38 +309,6 @@ public class ConfigControllerTest {
assertEquals
(
"foo"
,
result
.
getConfigurations
().
get
(
"apollo.public.bar"
));
}
@Test
public
void
testQueryConfigWithPublicNamespaceAndNoAppOverrideAndNoDataCenter
()
throws
Exception
{
String
someClientSideReleaseKey
=
"1"
;
String
someServerSideReleaseKey
=
"2"
;
HttpServletResponse
someResponse
=
mock
(
HttpServletResponse
.
class
);
String
somePublicAppId
=
"somePublicAppId"
;
AppNamespace
somePublicAppNamespace
=
assemblePublicAppNamespace
(
somePublicAppId
,
somePublicNamespaceName
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
somePublicNamespaceName
))
.
thenReturn
(
null
);
when
(
appNamespaceService
.
findPublicNamespaceByName
(
somePublicNamespaceName
))
.
thenReturn
(
somePublicAppNamespace
);
when
(
releaseService
.
findLatestActiveRelease
(
somePublicAppId
,
someDataCenter
,
somePublicNamespaceName
))
.
thenReturn
(
null
);
when
(
releaseService
.
findLatestActiveRelease
(
somePublicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespaceName
))
.
thenReturn
(
somePublicRelease
);
when
(
somePublicRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideReleaseKey
);
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
assertEquals
(
someServerSideReleaseKey
,
result
.
getReleaseKey
());
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someClusterName
,
result
.
getCluster
());
assertEquals
(
somePublicNamespaceName
,
result
.
getNamespaceName
());
assertEquals
(
"foo"
,
result
.
getConfigurations
().
get
(
"apollo.public.bar"
));
}
@Test
public
void
testQueryConfigWithPublicNamespaceAndAppOverride
()
throws
Exception
{
String
someAppSideReleaseKey
=
"1"
;
...
...
@@ -433,14 +323,14 @@ public class ConfigControllerTest {
when
(
somePublicRelease
.
getConfigurations
())
.
thenReturn
(
"{\"apollo.public.foo\": \"foo\", \"apollo.public.bar\": \"bar\"}"
);
when
(
releaseService
.
findLatestActiveRelease
(
someAppId
,
someClusterName
,
somePublicNamespaceName
))
.
thenReturn
(
someRelease
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
someAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
someRelease
);
when
(
someRelease
.
getReleaseKey
()).
thenReturn
(
someAppSideReleaseKey
);
when
(
someRelease
.
getNamespaceName
()).
thenReturn
(
somePublicNamespaceName
);
when
(
appNamespaceService
.
findPublicNamespaceByName
(
somePublicNamespaceName
))
.
thenReturn
(
somePublicAppNamespace
);
when
(
releaseService
.
findLatestActiveRelease
(
somePublicAppId
,
someDataCenter
,
somePublicNamespaceName
))
.
thenReturn
(
somePublicRelease
);
when
(
configService
.
loadConfig
(
someAppId
,
someClientIp
,
somePublicAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
somePublicRelease
);
when
(
somePublicRelease
.
getReleaseKey
()).
thenReturn
(
somePublicAppSideReleaseKey
);
when
(
somePublicRelease
.
getAppId
()).
thenReturn
(
somePublicAppId
);
when
(
somePublicRelease
.
getClusterName
()).
thenReturn
(
someDataCenter
);
...
...
@@ -449,7 +339,7 @@ public class ConfigControllerTest {
ApolloConfig
result
=
configController
.
queryConfig
(
someAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someAppSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someAppSideReleaseKey
,
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
assertEquals
(
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppSideReleaseKey
,
somePublicAppSideReleaseKey
),
...
...
@@ -510,9 +400,10 @@ public class ConfigControllerTest {
ApolloConfig
result
=
configController
.
queryConfig
(
appId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
verify
(
releaseService
,
never
()).
findLatestActiveRelease
(
appId
,
someClusterName
,
defaultNamespaceName
);
verify
(
configService
,
never
()).
loadConfig
(
appId
,
someClientIp
,
someAppId
,
someClusterName
,
defaultNamespaceName
,
someDataCenter
,
someNotificationMessages
);
verify
(
appNamespaceService
,
never
()).
findPublicNamespaceByName
(
defaultNamespaceName
);
assertNull
(
result
);
verify
(
someResponse
,
times
(
1
)).
sendError
(
eq
(
HttpServletResponse
.
SC_NOT_FOUND
),
anyString
());
...
...
@@ -530,15 +421,17 @@ public class ConfigControllerTest {
when
(
appNamespaceService
.
findPublicNamespaceByName
(
somePublicNamespaceName
))
.
thenReturn
(
somePublicAppNamespace
);
when
(
releaseService
.
findLatestActiveRelease
(
somePublicAppId
,
someDataCenter
,
somePublicNamespaceName
))
.
thenReturn
(
somePublicRelease
);
when
(
configService
.
loadConfig
(
appId
,
someClientIp
,
somePublicAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someNotificationMessages
))
.
thenReturn
(
somePublicRelease
);
when
(
somePublicRelease
.
getReleaseKey
()).
thenReturn
(
someServerSideReleaseKey
);
when
(
namespaceUtil
.
normalizeNamespace
(
appId
,
somePublicNamespaceName
)).
thenReturn
(
somePublicNamespaceName
);
ApolloConfig
result
=
configController
.
queryConfig
(
appId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someClientSideReleaseKey
,
someClientIp
,
someRequest
,
someResponse
);
someClientIp
,
some
MessagesAsString
,
some
Request
,
someResponse
);
verify
(
releaseService
,
never
()).
findLatestActiveRelease
(
appId
,
someClusterName
,
somePublicNamespaceName
);
verify
(
configService
,
never
()).
loadConfig
(
appId
,
someClientIp
,
appId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someNotificationMessages
);
assertEquals
(
someServerSideReleaseKey
,
result
.
getReleaseKey
());
assertEquals
(
appId
,
result
.
getAppId
());
assertEquals
(
someClusterName
,
result
.
getCluster
());
...
...
@@ -546,6 +439,30 @@ public class ConfigControllerTest {
assertEquals
(
"foo"
,
result
.
getConfigurations
().
get
(
"apollo.public.bar"
));
}
@Test
public
void
testTransformMessages
()
throws
Exception
{
String
someKey
=
"someKey"
;
long
someNotificationId
=
1
;
String
anotherKey
=
"anotherKey"
;
long
anotherNotificationId
=
2
;
ApolloNotificationMessages
notificationMessages
=
new
ApolloNotificationMessages
();
notificationMessages
.
put
(
someKey
,
someNotificationId
);
notificationMessages
.
put
(
anotherKey
,
anotherNotificationId
);
String
someMessagesAsString
=
gson
.
toJson
(
notificationMessages
);
ApolloNotificationMessages
result
=
configController
.
transformMessages
(
someMessagesAsString
);
assertEquals
(
notificationMessages
.
getDetails
(),
result
.
getDetails
());
}
@Test
public
void
testTransformInvalidMessages
()
throws
Exception
{
String
someInvalidMessages
=
"someInvalidMessages"
;
assertNull
(
configController
.
transformMessages
(
someInvalidMessages
));
}
private
AppNamespace
assemblePublicAppNamespace
(
String
appId
,
String
namespace
)
{
return
assembleAppNamespace
(
appId
,
namespace
,
true
);
}
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileControllerTest.java
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
2a834828
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
integration
;
import
com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages
;
import
com.google.common.base.Joiner
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Sets
;
...
...
@@ -28,6 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNotEquals
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
/**
* @author Jason Song(song_s@ctrip.com)
...
...
@@ -62,14 +64,14 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithDefaultNamespace
()
throws
Exception
{
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
someAppId
,
someCluster
,
defaultNamespace
),
stop
);
String
key
=
assembleKey
(
someAppId
,
someCluster
,
defaultNamespace
);
periodicSendMessage
(
executorService
,
key
,
stop
);
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
defaultNamespace
,
-
1
));
transformApolloConfigNotificationsToString
(
defaultNamespace
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
));
stop
.
set
(
true
);
...
...
@@ -78,20 +80,27 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
defaultNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertNotEquals
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithDefaultNamespaceAsFile
()
throws
Exception
{
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
someAppId
,
someCluster
,
defaultNamespace
),
String
key
=
assembleKey
(
someAppId
,
someCluster
,
defaultNamespace
);
periodicSendMessage
(
executorService
,
key
,
stop
);
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
defaultNamespace
+
".properties"
,
-
1
));
transformApolloConfigNotificationsToString
(
defaultNamespace
+
".properties"
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
));
stop
.
set
(
true
);
...
...
@@ -100,21 +109,27 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
defaultNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertNotEquals
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
messages
.
get
(
key
).
longValue
());
}
@Test
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithMultipleNamespaces
()
throws
Exception
{
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
someAppId
,
someCluster
,
somePublicNamespace
),
stop
);
String
key
=
assembleKey
(
someAppId
,
someCluster
,
somePublicNamespace
);
periodicSendMessage
(
executorService
,
key
,
stop
);
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
defaultNamespace
+
".properties"
,
-
1
,
defaultNamespace
,
-
1
,
somePublicNamespace
,
-
1
));
transformApolloConfigNotificationsToString
(
defaultNamespace
+
".properties"
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
defaultNamespace
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
somePublicNamespace
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
));
stop
.
set
(
true
);
...
...
@@ -123,6 +138,44 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertNotEquals
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
messages
.
get
(
key
).
longValue
());
}
@Test
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithMultipleNamespacesAndIncorrectCase
()
throws
Exception
{
AtomicBoolean
stop
=
new
AtomicBoolean
();
String
key
=
assembleKey
(
someAppId
,
someCluster
,
somePublicNamespace
);
periodicSendMessage
(
executorService
,
key
,
stop
);
String
someDefaultNamespaceWithIncorrectCase
=
defaultNamespace
.
toUpperCase
();
String
somePublicNamespaceWithIncorrectCase
=
somePublicNamespace
.
toUpperCase
();
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
defaultNamespace
+
".properties"
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
someDefaultNamespaceWithIncorrectCase
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
somePublicNamespaceWithIncorrectCase
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
));
stop
.
set
(
true
);
List
<
ApolloConfigNotification
>
notifications
=
result
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNamespaceWithIncorrectCase
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertNotEquals
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
...
...
@@ -131,15 +184,15 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
public
void
testPollNotificationWithPrivateNamespaceAsFile
()
throws
Exception
{
String
namespace
=
"someNamespace.xml"
;
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
someAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
namespace
),
stop
);
String
key
=
assembleKey
(
someAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
namespace
);
periodicSendMessage
(
executorService
,
key
,
stop
);
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
namespace
,
-
1
));
transformApolloConfigNotificationsToString
(
namespace
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
));
stop
.
set
(
true
);
...
...
@@ -148,6 +201,11 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
namespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertNotEquals
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
...
...
@@ -163,11 +221,19 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
defaultNamespace
,
someOutDatedNotificationId
));
long
newNotificationId
=
10
;
List
<
ApolloConfigNotification
>
notifications
=
result
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
defaultNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertEquals
(
10
,
notifications
.
get
(
0
).
getNotificationId
());
assertEquals
(
newNotificationId
,
notifications
.
get
(
0
).
getNotificationId
());
String
key
=
assembleKey
(
someAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
ConfigConsts
.
NAMESPACE_APPLICATION
);
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertEquals
(
newNotificationId
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
...
...
@@ -177,15 +243,14 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
String
publicAppId
=
"somePublicAppId"
;
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
),
stop
);
String
key
=
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
);
periodicSendMessage
(
executorService
,
key
,
stop
);
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
somePublicNamespace
,
-
1
));
transformApolloConfigNotificationsToString
(
somePublicNamespace
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
));
stop
.
set
(
true
);
...
...
@@ -194,6 +259,11 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertNotEquals
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
...
...
@@ -204,14 +274,15 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
String
someDC
=
"someDC"
;
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
publicAppId
,
someDC
,
somePublicNamespace
),
stop
);
String
key
=
assembleKey
(
publicAppId
,
someDC
,
somePublicNamespace
);
periodicSendMessage
(
executorService
,
key
,
stop
);
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}&dataCenter={dataCenter}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
somePublicNamespace
,
-
1
),
someDC
);
transformApolloConfigNotificationsToString
(
somePublicNamespace
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
),
someDC
);
stop
.
set
(
true
);
...
...
@@ -220,6 +291,11 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertNotEquals
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
...
...
@@ -231,14 +307,15 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
String
someDC
=
"someDC"
;
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
publicAppId
,
someDC
,
somePublicNamespace
),
stop
);
String
key
=
assembleKey
(
publicAppId
,
someDC
,
somePublicNamespace
);
periodicSendMessage
(
executorService
,
key
,
stop
);
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}&dataCenter={dataCenter}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
defaultNamespace
,
-
1
,
somePublicNamespace
,
-
1
),
transformApolloConfigNotificationsToString
(
defaultNamespace
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
somePublicNamespace
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
),
someDC
);
stop
.
set
(
true
);
...
...
@@ -248,6 +325,11 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertNotEquals
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
...
...
@@ -258,15 +340,15 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
String
someDC
=
"someDC"
;
AtomicBoolean
stop
=
new
AtomicBoolean
();
periodicSendMessage
(
executorService
,
assembleKey
(
publicAppId
,
someDC
,
somePublicNamespace
),
stop
);
String
key
=
assembleKey
(
publicAppId
,
someDC
,
somePublicNamespace
);
periodicSendMessage
(
executorService
,
key
,
stop
);
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}&dataCenter={dataCenter}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
somePublicNamespace
+
".properties"
,
-
1
),
someDC
);
transformApolloConfigNotificationsToString
(
somePublicNamespace
+
".properties"
,
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
),
someDC
);
stop
.
set
(
true
);
...
...
@@ -275,6 +357,11 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertNotEquals
(
ConfigConsts
.
NOTIFICATION_ID_PLACEHOLDER
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
...
...
@@ -282,6 +369,7 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
@Sql
(
scripts
=
"/integration-test/test-release-message.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithPublicNamespaceWithNotificationIdOutDated
()
throws
Exception
{
String
publicAppId
=
"somePublicAppId"
;
long
someOutDatedNotificationId
=
1
;
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
...
...
@@ -291,11 +379,151 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
transformApolloConfigNotificationsToString
(
somePublicNamespace
,
someOutDatedNotificationId
));
long
newNotificationId
=
20
;
List
<
ApolloConfigNotification
>
notifications
=
result
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
assertEquals
(
newNotificationId
,
notifications
.
get
(
0
).
getNotificationId
());
String
key
=
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
);
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertEquals
(
newNotificationId
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-message.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithMultiplePublicNamespaceWithIncorrectCaseWithNotificationIdOutDated
()
throws
Exception
{
String
publicAppId
=
"somePublicAppId"
;
long
someOutDatedNotificationId
=
1
;
long
newNotificationId
=
20
;
String
somePublicNameWithIncorrectCase
=
somePublicNamespace
.
toUpperCase
();
//the same namespace with difference character case, and difference notification id
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
somePublicNamespace
,
newNotificationId
,
somePublicNameWithIncorrectCase
,
someOutDatedNotificationId
));
List
<
ApolloConfigNotification
>
notifications
=
result
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNameWithIncorrectCase
,
notifications
.
get
(
0
).
getNamespaceName
());
assertEquals
(
newNotificationId
,
notifications
.
get
(
0
).
getNotificationId
());
String
key
=
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
);
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertEquals
(
newNotificationId
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-message.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithMultiplePublicNamespaceWithIncorrectCase2WithNotificationIdOutDated
()
throws
Exception
{
String
publicAppId
=
"somePublicAppId"
;
long
someOutDatedNotificationId
=
1
;
long
newNotificationId
=
20
;
String
somePublicNameWithIncorrectCase
=
somePublicNamespace
.
toUpperCase
();
//the same namespace with difference character case, and difference notification id
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
somePublicNameWithIncorrectCase
,
someOutDatedNotificationId
,
somePublicNamespace
,
newNotificationId
));
List
<
ApolloConfigNotification
>
notifications
=
result
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNameWithIncorrectCase
,
notifications
.
get
(
0
).
getNamespaceName
());
assertEquals
(
newNotificationId
,
notifications
.
get
(
0
).
getNotificationId
());
String
key
=
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
);
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertEquals
(
newNotificationId
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-message.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithMultiplePublicNamespaceWithIncorrectCase3WithNotificationIdOutDated
()
throws
Exception
{
String
publicAppId
=
"somePublicAppId"
;
long
someOutDatedNotificationId
=
1
;
long
newNotificationId
=
20
;
String
somePublicNameWithIncorrectCase
=
somePublicNamespace
.
toUpperCase
();
//the same namespace with difference character case, and difference notification id
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
somePublicNameWithIncorrectCase
,
newNotificationId
,
somePublicNamespace
,
someOutDatedNotificationId
));
List
<
ApolloConfigNotification
>
notifications
=
result
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertEquals
(
newNotificationId
,
notifications
.
get
(
0
).
getNotificationId
());
String
key
=
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
);
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertEquals
(
newNotificationId
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-message.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithMultiplePublicNamespaceWithIncorrectCase4WithNotificationIdOutDated
()
throws
Exception
{
String
publicAppId
=
"somePublicAppId"
;
long
someOutDatedNotificationId
=
1
;
long
newNotificationId
=
20
;
String
somePublicNameWithIncorrectCase
=
somePublicNamespace
.
toUpperCase
();
//the same namespace with difference character case, and difference notification id
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
somePublicNamespace
,
someOutDatedNotificationId
,
somePublicNameWithIncorrectCase
,
newNotificationId
));
List
<
ApolloConfigNotification
>
notifications
=
result
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
1
,
notifications
.
size
());
assertEquals
(
somePublicNamespace
,
notifications
.
get
(
0
).
getNamespaceName
());
assertEquals
(
newNotificationId
,
notifications
.
get
(
0
).
getNotificationId
());
String
key
=
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
);
ApolloNotificationMessages
messages
=
result
.
getBody
().
get
(
0
).
getMessages
();
assertEquals
(
1
,
messages
.
getDetails
().
size
());
assertTrue
(
messages
.
has
(
key
));
assertEquals
(
newNotificationId
,
messages
.
get
(
key
).
longValue
());
}
@Test
(
timeout
=
5000L
)
...
...
@@ -304,7 +532,10 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithMultipleNamespacesAndNotificationIdsOutDated
()
throws
Exception
{
String
publicAppId
=
"somePublicAppId"
;
long
someOutDatedNotificationId
=
1
;
long
newDefaultNamespaceNotificationId
=
10
;
long
newPublicNamespaceNotification
=
20
;
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
...
...
@@ -318,11 +549,87 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
assertEquals
(
2
,
notifications
.
size
());
Set
<
String
>
outDatedNamespaces
=
Sets
.
newHashSet
(
notifications
.
get
(
0
).
getNamespaceName
(),
notifications
.
get
(
1
).
getNamespaceName
());
Sets
.
newHashSet
(
notifications
.
get
(
0
).
getNamespaceName
(),
notifications
.
get
(
1
).
getNamespaceName
());
assertEquals
(
Sets
.
newHashSet
(
defaultNamespace
,
somePublicNamespace
),
outDatedNamespaces
);
assertNotEquals
(
0
,
notifications
.
get
(
0
).
getNotificationId
());
assertNotEquals
(
1
,
notifications
.
get
(
1
).
getNotificationId
());
Set
<
Long
>
newNotificationIds
=
Sets
.
newHashSet
(
notifications
.
get
(
0
).
getNotificationId
(),
notifications
.
get
(
1
).
getNotificationId
());
assertEquals
(
Sets
.
newHashSet
(
newDefaultNamespaceNotificationId
,
newPublicNamespaceNotification
),
newNotificationIds
);
String
defaultNamespaceKey
=
assembleKey
(
someAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
ConfigConsts
.
NAMESPACE_APPLICATION
);
String
publicNamespaceKey
=
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
);
ApolloNotificationMessages
firstMessages
=
notifications
.
get
(
0
).
getMessages
();
ApolloNotificationMessages
secondMessages
=
notifications
.
get
(
1
).
getMessages
();
assertEquals
(
1
,
firstMessages
.
getDetails
().
size
());
assertEquals
(
1
,
secondMessages
.
getDetails
().
size
());
assertTrue
(
(
firstMessages
.
has
(
defaultNamespaceKey
)
&&
firstMessages
.
get
(
defaultNamespaceKey
).
equals
(
newDefaultNamespaceNotificationId
))
||
(
firstMessages
.
has
(
publicNamespaceKey
)
&&
firstMessages
.
get
(
publicNamespaceKey
).
equals
(
newPublicNamespaceNotification
))
);
assertTrue
(
(
secondMessages
.
has
(
defaultNamespaceKey
)
&&
secondMessages
.
get
(
defaultNamespaceKey
).
equals
(
newDefaultNamespaceNotificationId
))
||
(
secondMessages
.
has
(
publicNamespaceKey
)
&&
secondMessages
.
get
(
publicNamespaceKey
).
equals
(
newPublicNamespaceNotification
))
);
}
@Test
(
timeout
=
5000L
)
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-message.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testPollNotificationWithMultipleNamespacesAndNotificationIdsOutDatedAndIncorrectCase
()
throws
Exception
{
String
publicAppId
=
"somePublicAppId"
;
long
someOutDatedNotificationId
=
1
;
long
newDefaultNamespaceNotificationId
=
10
;
long
newPublicNamespaceNotification
=
20
;
String
someDefaultNamespaceWithIncorrectCase
=
defaultNamespace
.
toUpperCase
();
String
somePublicNamespaceWithIncorrectCase
=
somePublicNamespace
.
toUpperCase
();
ResponseEntity
<
List
<
ApolloConfigNotification
>>
result
=
restTemplate
.
exchange
(
"{baseurl}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}"
,
HttpMethod
.
GET
,
null
,
typeReference
,
getHostUrl
(),
someAppId
,
someCluster
,
transformApolloConfigNotificationsToString
(
somePublicNamespaceWithIncorrectCase
,
someOutDatedNotificationId
,
someDefaultNamespaceWithIncorrectCase
,
someOutDatedNotificationId
));
List
<
ApolloConfigNotification
>
notifications
=
result
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
2
,
notifications
.
size
());
Set
<
String
>
outDatedNamespaces
=
Sets
.
newHashSet
(
notifications
.
get
(
0
).
getNamespaceName
(),
notifications
.
get
(
1
).
getNamespaceName
());
assertEquals
(
Sets
.
newHashSet
(
someDefaultNamespaceWithIncorrectCase
,
somePublicNamespaceWithIncorrectCase
),
outDatedNamespaces
);
Set
<
Long
>
newNotificationIds
=
Sets
.
newHashSet
(
notifications
.
get
(
0
).
getNotificationId
(),
notifications
.
get
(
1
).
getNotificationId
());
assertEquals
(
Sets
.
newHashSet
(
newDefaultNamespaceNotificationId
,
newPublicNamespaceNotification
),
newNotificationIds
);
String
defaultNamespaceKey
=
assembleKey
(
someAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
ConfigConsts
.
NAMESPACE_APPLICATION
);
String
publicNamespaceKey
=
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
);
ApolloNotificationMessages
firstMessages
=
notifications
.
get
(
0
).
getMessages
();
ApolloNotificationMessages
secondMessages
=
notifications
.
get
(
1
).
getMessages
();
assertEquals
(
1
,
firstMessages
.
getDetails
().
size
());
assertEquals
(
1
,
secondMessages
.
getDetails
().
size
());
assertTrue
(
(
firstMessages
.
has
(
defaultNamespaceKey
)
&&
firstMessages
.
get
(
defaultNamespaceKey
).
equals
(
newDefaultNamespaceNotificationId
))
||
(
firstMessages
.
has
(
publicNamespaceKey
)
&&
firstMessages
.
get
(
publicNamespaceKey
).
equals
(
newPublicNamespaceNotification
))
);
assertTrue
(
(
secondMessages
.
has
(
defaultNamespaceKey
)
&&
secondMessages
.
get
(
defaultNamespaceKey
).
equals
(
newDefaultNamespaceNotificationId
))
||
(
secondMessages
.
has
(
publicNamespaceKey
)
&&
secondMessages
.
get
(
publicNamespaceKey
).
equals
(
newPublicNamespaceNotification
))
);
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
)
{
...
...
@@ -359,9 +666,7 @@ public class NotificationControllerV2IntegrationTest extends AbstractBaseIntegra
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
;
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/service/AppNamespaceServiceWithCacheTest.java
View file @
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
)));
}
...
...
@@ -210,4 +266,4 @@ public class AppNamespaceServiceWithCacheTest {
appNamespace
.
setDataChangeLastModifiedTime
(
new
Date
());
return
appNamespace
;
}
}
\ No newline at end of file
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/service/config/ConfigServiceWithCacheTest.java
0 → 100644
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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 */
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment