diff --git a/apollo-mockserver/pom.xml b/apollo-mockserver/pom.xml
index 48a4f238b341a4b3dd899184db3f4c64c01a1ab4..d2c09b551183d81f2a688f193fa86fb917025322 100644
--- a/apollo-mockserver/pom.xml
+++ b/apollo-mockserver/pom.xml
@@ -11,27 +11,38 @@
apollo-mockserver
+
+
+
+ com.squareup.okhttp3
+ mockwebserver
+ 3.11.0
+
+
+ com.squareup.okhttp3
+ okhttp
+ 3.11.0
+
+
+
+
com.ctrip.framework.apollo
apollo-client
- ${project.version}
com.squareup.okhttp3
mockwebserver
- 3.11.0
com.squareup.okhttp3
okhttp
- 3.11.0
org.springframework.boot
spring-boot-starter
- 1.3.8.RELEASE
- provided
+ test
diff --git a/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java b/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java
index 89d8aad994c7a642d94493b69fda9249b98f17f8..c616c4bb3e91dcd087a60dbd7df119674977dc2b 100644
--- a/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java
+++ b/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java
@@ -1,19 +1,19 @@
package com.ctrip.framework.apollo.mockserver;
-import com.ctrip.framework.apollo.core.MetaDomainConsts;
+import com.ctrip.framework.apollo.build.ApolloInjector;
import com.ctrip.framework.apollo.core.dto.ApolloConfig;
import com.ctrip.framework.apollo.core.dto.ApolloConfigNotification;
-import com.ctrip.framework.apollo.core.dto.ServiceDTO;
-import com.ctrip.framework.apollo.core.spi.MetaServerProvider;
import com.ctrip.framework.apollo.core.utils.ResourceUtils;
+import com.ctrip.framework.apollo.internals.ConfigServiceLocator;
+import com.ctrip.framework.apollo.spring.config.PropertySourcesProcessor;
+import com.ctrip.framework.apollo.spring.property.SpringValueDefinitionProcessor;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
-import java.io.IOException;
+import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -29,40 +29,57 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Create by zhangzheng on 8/22/18
- * Email:zhangzheng@youzan.com
+ * Create by zhangzheng on 8/22/18 Email:zhangzheng@youzan.com
*/
public class EmbeddedApollo extends ExternalResource {
- private Gson gson = new Gson();
- private Logger logger = LoggerFactory.getLogger(EmbeddedApollo.class);
- private Type notificationType = new TypeToken>(){}.getType();
+ private static final Logger logger = LoggerFactory.getLogger(EmbeddedApollo.class);
+ private static final Type notificationType = new TypeToken>() {
+ }.getType();
+
+ private static Method PROPERTY_SOURCES_PROCESSOR_CLEAR;
+ private static Method SPRING_VALUE_DEFINITION_PROCESS_CLEAR;
+ private static Method CONFIG_SERVICE_LOCATOR_CLEAR;
+ private static ConfigServiceLocator CONFIG_SERVICE_LOCATOR;
+
+ private final Gson gson = new Gson();
+ private final Map> addedOrModifiedPropertiesOfNamespace = new HashMap<>();
+ private final Map> deletedKeysOfNamespace = new HashMap<>();
- private String listenningUrl;
private MockWebServer server;
+ static {
+ try {
+ System.setProperty("apollo.longPollingInitialDelayInMills", "0");
+ PROPERTY_SOURCES_PROCESSOR_CLEAR = PropertySourcesProcessor.class.getDeclaredMethod("reset");
+ PROPERTY_SOURCES_PROCESSOR_CLEAR.setAccessible(true);
+ SPRING_VALUE_DEFINITION_PROCESS_CLEAR = SpringValueDefinitionProcessor.class.getDeclaredMethod("reset");
+ SPRING_VALUE_DEFINITION_PROCESS_CLEAR.setAccessible(true);
+ CONFIG_SERVICE_LOCATOR = ApolloInjector.getInstance(ConfigServiceLocator.class);
+ CONFIG_SERVICE_LOCATOR_CLEAR = ConfigServiceLocator.class.getDeclaredMethod("initConfigServices");
+ CONFIG_SERVICE_LOCATOR_CLEAR.setAccessible(true);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ }
@Override
protected void before() throws Throwable {
+ clear();
server = new MockWebServer();
final Dispatcher dispatcher = new Dispatcher() {
@Override
public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
- if (request.getPath().startsWith("/services/config")) {
-
- return new MockResponse().setResponseCode(200)
- .setBody(mockConfigServiceAddr(listenningUrl));
- } else if (request.getPath().startsWith("/notifications/v2")) {
+ if (request.getPath().startsWith("/notifications/v2")) {
String notifications = request.getRequestUrl().queryParameter("notifications");
- MockResponse response = new MockResponse().setResponseCode(200).setBody(mockLongPollBody(notifications));
- return response;
+ return new MockResponse().setResponseCode(200).setBody(mockLongPollBody(notifications));
} else if (request.getPath().startsWith("/configs")) {
List pathSegments = request.getRequestUrl().pathSegments();
+ // appId and cluster might be used in the future
String appId = pathSegments.get(1);
String cluster = pathSegments.get(2);
String namespace = pathSegments.get(3);
- return new MockResponse().setResponseCode(200)
- .setBody(loadConfigFor(namespace));
+ return new MockResponse().setResponseCode(200).setBody(loadConfigFor(namespace));
}
return new MockResponse().setResponseCode(404);
}
@@ -70,13 +87,8 @@ public class EmbeddedApollo extends ExternalResource {
server.setDispatcher(dispatcher);
server.start();
- //指定apollo的metaserver地址为localhost
- int port = server.getPort();
- this.listenningUrl = "http://localhost:"+port;
- MockedMetaServerProvider.setAddress(listenningUrl);
-
- System.setProperty("apollo.longPollingInitialDelayInMills","1");
+ mockConfigServiceUrl("http://localhost:" + server.getPort());
super.before();
}
@@ -84,78 +96,90 @@ public class EmbeddedApollo extends ExternalResource {
@Override
protected void after() {
try {
+ clear();
server.close();
- } catch (IOException e) {
+ } catch (Exception e) {
logger.error("stop apollo server error", e);
}
}
+ private void clear() throws Exception {
+ resetOverriddenProperties();
+ // clear Apollo states
+ PROPERTY_SOURCES_PROCESSOR_CLEAR.invoke(null);
+ SPRING_VALUE_DEFINITION_PROCESS_CLEAR.invoke(null);
+ }
+
+ private void mockConfigServiceUrl(String url) throws Exception {
+ System.setProperty("apollo.configService", url);
- private String loadConfigFor(String namespace){
+ CONFIG_SERVICE_LOCATOR_CLEAR.invoke(CONFIG_SERVICE_LOCATOR);
+ }
+
+ private String loadConfigFor(String namespace) {
String filename = String.format("mockdata-%s.properties", namespace);
final Properties prop = ResourceUtils.readConfigFile(filename, new Properties());
- Map configurations = prop.stringPropertyNames().stream().collect(
- Collectors.toMap(key -> key, key -> prop.getProperty(key)));
- ApolloConfig apolloConfig = new ApolloConfig("someAppId", "someCluster",namespace,"someReleaseKey");
+ Map configurations = prop.stringPropertyNames().stream().collect(
+ Collectors.toMap(key -> key, prop::getProperty));
+ ApolloConfig apolloConfig = new ApolloConfig("someAppId", "someCluster", namespace, "someReleaseKey");
- Map mergedConfigurations = mergeModifyByUser(namespace, configurations);
+ Map mergedConfigurations = mergeOverriddenProperties(namespace, configurations);
apolloConfig.setConfigurations(mergedConfigurations);
return gson.toJson(apolloConfig);
}
-
- private String mockLongPollBody(String notificationsStr){
+ private String mockLongPollBody(String notificationsStr) {
List oldNotifications = gson.fromJson(notificationsStr, notificationType);
List newNotifications = new ArrayList<>();
- for(ApolloConfigNotification noti: oldNotifications){
- newNotifications.add(new ApolloConfigNotification(noti.getNamespaceName(), noti.getNotificationId()+1));
+ for (ApolloConfigNotification notification : oldNotifications) {
+ newNotifications
+ .add(new ApolloConfigNotification(notification.getNamespaceName(), notification.getNotificationId() + 1));
}
return gson.toJson(newNotifications);
}
- private String mockConfigServiceAddr(String addr){
- ServiceDTO serviceDTO = new ServiceDTO();
- serviceDTO.setAppName("someAppName");
- serviceDTO.setInstanceId("someInstanceId");
- serviceDTO.setHomepageUrl(addr);
- return gson.toJson(Arrays.asList(serviceDTO));
- }
-
/**
* 合并用户对namespace的修改
- * @param configurations
- * @return
*/
- private Map mergeModifyByUser(String namespace
- , Map configurations){
- if(addedPropertyOfNamespace.containsKey(namespace)){
- configurations.putAll(addedPropertyOfNamespace.get(namespace));
+ private Map mergeOverriddenProperties(String namespace, Map configurations) {
+ if (addedOrModifiedPropertiesOfNamespace.containsKey(namespace)) {
+ configurations.putAll(addedOrModifiedPropertiesOfNamespace.get(namespace));
}
- if(deletedKeysOfNamespace.containsKey(namespace)){
- for(String k: deletedKeysOfNamespace.get(namespace)){
+ if (deletedKeysOfNamespace.containsKey(namespace)) {
+ for (String k : deletedKeysOfNamespace.get(namespace)) {
configurations.remove(k);
}
}
return configurations;
}
-
- private Map> addedPropertyOfNamespace = new HashMap<>();
- public void addOrModifyPropery(String namespace, String someKey, String someValue) {
- if(addedPropertyOfNamespace.containsKey(namespace)){
- addedPropertyOfNamespace.get(namespace).put(someKey, someValue);
- }else{
- addedPropertyOfNamespace.put(namespace, ImmutableMap.of(someKey, someValue));
+ /**
+ * Add new property or update existed property
+ */
+ public void addOrModifyProperty(String namespace, String someKey, String someValue) {
+ if (addedOrModifiedPropertiesOfNamespace.containsKey(namespace)) {
+ addedOrModifiedPropertiesOfNamespace.get(namespace).put(someKey, someValue);
+ } else {
+ addedOrModifiedPropertiesOfNamespace.put(namespace, ImmutableMap.of(someKey, someValue));
}
}
- private Map> deletedKeysOfNamespace = new HashMap<>();
- public void delete(String namespace, String someKey) {
- if(deletedKeysOfNamespace.containsKey(namespace)){
+
+ /**
+ * Delete existed property
+ */
+ public void deleteProperty(String namespace, String someKey) {
+ if (deletedKeysOfNamespace.containsKey(namespace)) {
deletedKeysOfNamespace.get(namespace).add(someKey);
- }else{
+ } else {
deletedKeysOfNamespace.put(namespace, ImmutableSet.of(someKey));
}
}
-
+ /**
+ * reset overridden properties
+ */
+ public void resetOverriddenProperties() {
+ addedOrModifiedPropertiesOfNamespace.clear();
+ deletedKeysOfNamespace.clear();
+ }
}
diff --git a/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/MockedMetaServerProvider.java b/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/MockedMetaServerProvider.java
deleted file mode 100644
index 2c5fedafbcc943ff0fea7402bdf04b1bca502037..0000000000000000000000000000000000000000
--- a/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/MockedMetaServerProvider.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.ctrip.framework.apollo.mockserver;
-
-import com.ctrip.framework.apollo.core.enums.Env;
-import com.ctrip.framework.apollo.core.spi.MetaServerProvider;
-
-/**
- * Create by zhangzheng on 8/23/18
- * Email:zhangzheng@youzan.com
- */
-public class MockedMetaServerProvider implements MetaServerProvider{
-
- private static String address;
-
- public static void setAddress(String addr){
- address = addr;
- }
-
- @Override
- public String getMetaServerAddress(Env targetEnv) {
- return address;
- }
-
- @Override
- public int getOrder() {
- return HIGHEST_PRECEDENCE;
- }
-}
diff --git a/apollo-mockserver/src/main/resources/META-INF/services/com.ctrip.framework.apollo.core.spi.MetaServerProvider b/apollo-mockserver/src/main/resources/META-INF/services/com.ctrip.framework.apollo.core.spi.MetaServerProvider
deleted file mode 100644
index a3fe43116b984be01a94e148c03875cb78b7bf66..0000000000000000000000000000000000000000
--- a/apollo-mockserver/src/main/resources/META-INF/services/com.ctrip.framework.apollo.core.spi.MetaServerProvider
+++ /dev/null
@@ -1 +0,0 @@
-com.ctrip.framework.apollo.mockserver.MockedMetaServerProvider
diff --git a/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerApiTest.java b/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerApiTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f62cb8dc88dbd8b918efc71c3e2df2167341c29
--- /dev/null
+++ b/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerApiTest.java
@@ -0,0 +1,51 @@
+package com.ctrip.framework.apollo.mockserver;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.ctrip.framework.apollo.Config;
+import com.ctrip.framework.apollo.ConfigService;
+import com.ctrip.framework.apollo.model.ConfigChangeEvent;
+import com.google.common.util.concurrent.SettableFuture;
+import java.util.concurrent.TimeUnit;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+public class ApolloMockServerApiTest {
+
+ private static final String otherNamespace = "otherNamespace";
+
+ @ClassRule
+ public static EmbeddedApollo embeddedApollo = new EmbeddedApollo();
+
+ @Test
+ public void testGetProperty() throws Exception {
+ Config applicationConfig = ConfigService.getAppConfig();
+
+ assertEquals("value1", applicationConfig.getProperty("key1", null));
+ assertEquals("value2", applicationConfig.getProperty("key2", null));
+ }
+
+ @Test
+ public void testUpdateProperties() throws Exception {
+ String someNewValue = "someNewValue";
+
+ Config otherConfig = ConfigService.getConfig(otherNamespace);
+
+ SettableFuture future = SettableFuture.create();
+
+ otherConfig.addChangeListener(future::set);
+
+ assertEquals("otherValue1", otherConfig.getProperty("key1", null));
+ assertEquals("otherValue2", otherConfig.getProperty("key2", null));
+
+ embeddedApollo.addOrModifyProperty(otherNamespace, "key1", someNewValue);
+
+ ConfigChangeEvent changeEvent = future.get(5, TimeUnit.SECONDS);
+
+ assertEquals(someNewValue, otherConfig.getProperty("key1", null));
+ assertEquals("otherValue2", otherConfig.getProperty("key2", null));
+
+ assertTrue(changeEvent.isChanged("key1"));
+ }
+}
diff --git a/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/SpringIntegrationTest.java b/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerSpringIntegrationTest.java
similarity index 73%
rename from apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/SpringIntegrationTest.java
rename to apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerSpringIntegrationTest.java
index 525fe356433b3ac9a637cb21821bca0670fecd6c..ab24de4372a0519bc515671095b49e20beef8f12 100644
--- a/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/SpringIntegrationTest.java
+++ b/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerSpringIntegrationTest.java
@@ -1,12 +1,12 @@
package com.ctrip.framework.apollo.mockserver;
+import static org.junit.Assert.assertEquals;
+
import com.ctrip.framework.apollo.enums.PropertyChangeType;
-import com.ctrip.framework.apollo.mockserver.SpringIntegrationTest.TestConfiguration;
+import com.ctrip.framework.apollo.mockserver.ApolloMockServerSpringIntegrationTest.TestConfiguration;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
-import static org.junit.Assert.*;
-
import com.google.common.util.concurrent.SettableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@@ -23,21 +23,23 @@ import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
- * Create by zhangzheng on 8/16/18
- * Email:zhangzheng@youzan.com
+ * Create by zhangzheng on 8/16/18 Email:zhangzheng@youzan.com
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
-public class SpringIntegrationTest {
- @Autowired
- TestBean testBean;
+public class ApolloMockServerSpringIntegrationTest {
+
+ private static final String otherNamespace = "otherNamespace";
@ClassRule
public static EmbeddedApollo embeddedApollo = new EmbeddedApollo();
+ @Autowired
+ private TestBean testBean;
+
@Test
@DirtiesContext
- public void testPropertyInject(){
+ public void testPropertyInject() {
assertEquals("value1", testBean.key1);
assertEquals("value2", testBean.key2);
}
@@ -45,8 +47,7 @@ public class SpringIntegrationTest {
@Test
@DirtiesContext
public void testListenerTriggeredByAdd() throws InterruptedException, ExecutionException, TimeoutException {
- String otherNamespace = "othernamespace";
- embeddedApollo.addOrModifyPropery(otherNamespace,"someKey","someValue");
+ embeddedApollo.addOrModifyProperty(otherNamespace, "someKey", "someValue");
ConfigChangeEvent changeEvent = testBean.futureData.get(5000, TimeUnit.MILLISECONDS);
assertEquals(otherNamespace, changeEvent.getNamespace());
assertEquals("someValue", changeEvent.getChange("someKey").getNewValue());
@@ -56,42 +57,34 @@ public class SpringIntegrationTest {
@DirtiesContext
public void testListenerTriggeredByDel()
throws InterruptedException, ExecutionException, TimeoutException {
- String otherNamespace = "othernamespace";
- embeddedApollo.delete(otherNamespace, "key1");
+ embeddedApollo.deleteProperty(otherNamespace, "key1");
ConfigChangeEvent changeEvent = testBean.futureData.get(5000, TimeUnit.MILLISECONDS);
assertEquals(otherNamespace, changeEvent.getNamespace());
assertEquals(PropertyChangeType.DELETED, changeEvent.getChange("key1").getChangeType());
}
-
-
-
-
-
-
-
- @EnableApolloConfig("application")
+ @EnableApolloConfig
@Configuration
- static class TestConfiguration{
+ static class TestConfiguration {
+
@Bean
- public TestBean testBean(){
+ public TestBean testBean() {
return new TestBean();
}
}
- static class TestBean{
+ private static class TestBean {
+
@Value("${key1:default}")
- String key1;
+ private String key1;
@Value("${key2:default}")
- String key2;
+ private String key2;
- SettableFuture futureData = SettableFuture.create();
+ private SettableFuture futureData = SettableFuture.create();
- @ApolloConfigChangeListener("othernamespace")
+ @ApolloConfigChangeListener(otherNamespace)
private void onChange(ConfigChangeEvent changeEvent) {
futureData.set(changeEvent);
}
}
-
-
}
diff --git a/apollo-mockserver/src/test/resources/META-INF/app.properties b/apollo-mockserver/src/test/resources/META-INF/app.properties
new file mode 100644
index 0000000000000000000000000000000000000000..dca1d42b34fbce3488ecdcd0579d13677b192068
--- /dev/null
+++ b/apollo-mockserver/src/test/resources/META-INF/app.properties
@@ -0,0 +1 @@
+app.id=someAppId
diff --git a/apollo-mockserver/src/test/resources/mockdata-otherNamespace.properties b/apollo-mockserver/src/test/resources/mockdata-otherNamespace.properties
new file mode 100644
index 0000000000000000000000000000000000000000..9f6e4ac5dc1d1f3507de220f1ffaa512cc780eca
--- /dev/null
+++ b/apollo-mockserver/src/test/resources/mockdata-otherNamespace.properties
@@ -0,0 +1,2 @@
+key1=otherValue1
+key2=otherValue2
diff --git a/apollo-mockserver/src/test/resources/mockdata-othernamespace.properties b/apollo-mockserver/src/test/resources/mockdata-othernamespace.properties
deleted file mode 100644
index 26190d146cddba9395020b60589b47d9c046f66f..0000000000000000000000000000000000000000
--- a/apollo-mockserver/src/test/resources/mockdata-othernamespace.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-key1=othervalue1
-key2=othervalue2
diff --git a/pom.xml b/pom.xml
index ee5d0b68d88840b0faa07de84756395dd947b285..c693eebfd7ae6886ad57e15ad975841cb15496cf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -113,6 +113,11 @@
apollo-core
${project.version}
+
+ com.ctrip.framework.apollo
+ apollo-client
+ ${project.version}
+
com.ctrip.framework.apollo
apollo-common