You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by vi...@apache.org on 2019/08/29 08:49:51 UTC

[dubbo] 07/08: unit test

This is an automated email from the ASF dual-hosted git repository.

victory pushed a commit to branch cloud-native
in repository https://gitbox.apache.org/repos/asf/dubbo.git

commit ef4415e82545254de1da7e8d4840531cf5abf622
Author: cvictory <sh...@gmail.com>
AuthorDate: Thu Aug 29 16:46:00 2019 +0800

    unit test
---
 .../store/InMemoryWritableMetadataService.java     |  52 +++++-
 .../store/RemoteWritableMetadataService.java       |  30 ++--
 .../RemoteWritableMetadataServiceDelegate.java     |  14 +-
 .../store/InMemoryWritableMetadataServiceTest.java |  79 +++++++++
 .../store/RemoteWritableMeatadataServiceTest.java  |  88 ++++++++--
 .../RemoteWritableMetadataServiceDelegateTest.java | 183 +++++++++++++++++++++
 .../metadata/test/JTestMetadataReport4Test.java    |  13 +-
 7 files changed, 415 insertions(+), 44 deletions(-)

diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataService.java
index 7c34e67..749f234 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataService.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataService.java
@@ -17,6 +17,8 @@
 package org.apache.dubbo.metadata.store;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.metadata.MetadataService;
 import org.apache.dubbo.metadata.WritableMetadataService;
@@ -25,11 +27,14 @@ import org.apache.dubbo.metadata.definition.model.ServiceDefinition;
 
 import com.google.gson.Gson;
 
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.Map;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -46,19 +51,42 @@ import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
  *
  * @see MetadataService
  * @see WritableMetadataService
- * @since 2.7.4
+ * @since 2.7.5
  */
-public class InMemoryWritableMetadataService extends BaseWritableMetadataService implements WritableMetadataService {
-
+public class InMemoryWritableMetadataService implements WritableMetadataService {
 
+    final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final Lock lock = new ReentrantLock();
 
+    // =================================== Registration =================================== //
+
+    /**
+     * All exported {@link URL urls} {@link Map} whose key is the return value of {@link URL#getServiceKey()} method
+     * and value is the {@link SortedSet sorted set} of the {@link URL URLs}
+     */
+    ConcurrentNavigableMap<String, SortedSet<URL>> exportedServiceURLs = new ConcurrentSkipListMap<>();
+
     // ==================================================================================== //
 
+    // =================================== Subscription =================================== //
+
+    /**
+     * The subscribed {@link URL urls} {@link Map} of {@link MetadataService},
+     * whose key is the return value of {@link URL#getServiceKey()} method and value is
+     * the {@link SortedSet sorted set} of the {@link URL URLs}
+     */
+    ConcurrentNavigableMap<String, SortedSet<URL>> subscribedServiceURLs = new ConcurrentSkipListMap<>();
+
+    ConcurrentNavigableMap<String, String> serviceDefinitions = new ConcurrentSkipListMap<>();
+
     @Override
     public SortedSet<String> getSubscribedURLs() {
-        return super.getSubscribedURLs();
+        return getAllUnmodifiableServiceURLs(subscribedServiceURLs);
+    }
+
+    SortedSet<String> getAllUnmodifiableServiceURLs(Map<String, SortedSet<URL>> serviceURLs) {
+        return MetadataService.toSortedStrings(serviceURLs.values().stream().flatMap(Collection::stream));
     }
 
     @Override
@@ -129,8 +157,14 @@ public class InMemoryWritableMetadataService extends BaseWritableMetadataService
 
     boolean removeURL(Map<String, SortedSet<URL>> serviceURLs, URL url) {
         return executeMutually(() -> {
-            SortedSet<URL> urls = serviceURLs.getOrDefault(url.getServiceKey(), emptySortedSet());
-            return urls.remove(url);
+            String key = url.getServiceKey();
+            SortedSet<URL> urls = serviceURLs.getOrDefault(key, emptySortedSet());
+            boolean r = urls.remove(url);
+            // if it is empty
+            if (urls.isEmpty()) {
+                serviceURLs.remove(key);
+            }
+            return r;
         });
     }
 
@@ -155,8 +189,8 @@ public class InMemoryWritableMetadataService extends BaseWritableMetadataService
         return success;
     }
 
-    private static SortedSet<String> getServiceURLs(Map<String, SortedSet<URL>> exportedServiceURLs, String serviceKey,
-                                                    String protocol) {
+    private SortedSet<String> getServiceURLs(Map<String, SortedSet<URL>> exportedServiceURLs, String serviceKey,
+                                             String protocol) {
 
         SortedSet<URL> serviceURLs = exportedServiceURLs.get(serviceKey);
 
@@ -167,7 +201,7 @@ public class InMemoryWritableMetadataService extends BaseWritableMetadataService
         return MetadataService.toSortedStrings(serviceURLs.stream().filter(url -> isAcceptableProtocol(protocol, url)));
     }
 
-    private static boolean isAcceptableProtocol(String protocol, URL url) {
+    private boolean isAcceptableProtocol(String protocol, URL url) {
         return protocol == null
                 || protocol.equals(url.getParameter(PROTOCOL_KEY))
                 || protocol.equals(url.getProtocol());
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataService.java
index 90181ee..22c028d 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataService.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataService.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.metadata.store;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.metadata.WritableMetadataService;
 import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;
@@ -54,13 +55,15 @@ import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
  *
  * @since 2.7.5
  */
-public class RemoteWritableMetadataService extends BaseWritableMetadataService implements WritableMetadataService {
+public class RemoteWritableMetadataService implements WritableMetadataService {
 
     protected final Logger logger = LoggerFactory.getLogger(getClass());
     private volatile String exportedRevision;
     private volatile String subscribedRevision;
+    private InMemoryWritableMetadataService writableMetadataService;
 
-    public RemoteWritableMetadataService() {
+    public RemoteWritableMetadataService(InMemoryWritableMetadataService writableMetadataService) {
+        this.writableMetadataService = writableMetadataService;
     }
 
     public MetadataReport getMetadataReport() {
@@ -93,13 +96,15 @@ public class RemoteWritableMetadataService extends BaseWritableMetadataService i
     public void publishProvider(URL providerUrl) throws RpcException {
         //first add into the list
         // remove the individul param
-        providerUrl = providerUrl.removeParameters(PID_KEY, TIMESTAMP_KEY, Constants.BIND_IP_KEY, Constants.BIND_PORT_KEY, TIMESTAMP_KEY);
+        providerUrl = providerUrl.removeParameters(PID_KEY, TIMESTAMP_KEY, Constants.BIND_IP_KEY,
+                Constants.BIND_PORT_KEY, TIMESTAMP_KEY);
 
         try {
             String interfaceName = providerUrl.getParameter(INTERFACE_KEY);
             if (StringUtils.isNotEmpty(interfaceName)) {
                 Class interfaceClass = Class.forName(interfaceName);
-                FullServiceDefinition fullServiceDefinition = ServiceDefinitionBuilder.buildFullDefinition(interfaceClass, providerUrl.getParameters());
+                FullServiceDefinition fullServiceDefinition = ServiceDefinitionBuilder.buildFullDefinition(interfaceClass,
+                        providerUrl.getParameters());
                 getMetadataReport().storeProviderMetadata(new MetadataIdentifier(providerUrl.getServiceInterface(),
                         providerUrl.getParameter(VERSION_KEY), providerUrl.getParameter(GROUP_KEY),
                         PROVIDER_SIDE, providerUrl.getParameter(APPLICATION_KEY)), fullServiceDefinition);
@@ -114,7 +119,8 @@ public class RemoteWritableMetadataService extends BaseWritableMetadataService i
 
     @Deprecated
     public void publishConsumer(URL consumerURL) throws RpcException {
-        consumerURL = consumerURL.removeParameters(PID_KEY, TIMESTAMP_KEY, Constants.BIND_IP_KEY, Constants.BIND_PORT_KEY, TIMESTAMP_KEY);
+        consumerURL = consumerURL.removeParameters(PID_KEY, TIMESTAMP_KEY, Constants.BIND_IP_KEY,
+                Constants.BIND_PORT_KEY, TIMESTAMP_KEY);
         getMetadataReport().storeConsumerMetadata(new MetadataIdentifier(consumerURL.getServiceInterface(),
                 consumerURL.getParameter(VERSION_KEY), consumerURL.getParameter(GROUP_KEY), CONSUMER_SIDE,
                 consumerURL.getParameter(APPLICATION_KEY)), consumerURL.getParameters());
@@ -153,12 +159,14 @@ public class RemoteWritableMetadataService extends BaseWritableMetadataService i
                 result = false;
             }
         }
-        if (!StringUtils.isEmpty(subscribedRevision) && !subscribedRevision.equals(this.subscribedRevision)) {
+        if (!StringUtils.isEmpty(subscribedRevision) && !subscribedRevision.equals(this.subscribedRevision)
+                && CollectionUtils.isNotEmpty(writableMetadataService.getSubscribedURLs())) {
             this.subscribedRevision = subscribedRevision;
             SubscriberMetadataIdentifier metadataIdentifier = new SubscriberMetadataIdentifier();
             metadataIdentifier.setApplication(serviceName());
             metadataIdentifier.setRevision(subscribedRevision);
-            boolean executeResult = throwableAction(getMetadataReport()::saveSubscribedData, metadataIdentifier, super.getSubscribedURLs());
+            boolean executeResult = throwableAction(getMetadataReport()::saveSubscribedData, metadataIdentifier,
+                    writableMetadataService.getSubscribedURLs());
             if (!executeResult) {
                 result = false;
             }
@@ -168,7 +176,7 @@ public class RemoteWritableMetadataService extends BaseWritableMetadataService i
 
     private boolean saveServiceMetadata() {
         boolean result = true;
-        for (SortedSet<URL> urls : exportedServiceURLs.values()) {
+        for (SortedSet<URL> urls : writableMetadataService.exportedServiceURLs.values()) {
             Iterator<URL> iterator = urls.iterator();
             while (iterator.hasNext()) {
                 URL url = iterator.next();
@@ -200,7 +208,8 @@ public class RemoteWritableMetadataService extends BaseWritableMetadataService i
         return null;
     }
 
-    boolean throwableAction(BiConsumer<ServiceMetadataIdentifier, URL> consumer, ServiceMetadataIdentifier metadataIdentifier, URL url) {
+    boolean throwableAction(BiConsumer<ServiceMetadataIdentifier, URL> consumer,
+                            ServiceMetadataIdentifier metadataIdentifier, URL url) {
         try {
             consumer.accept(metadataIdentifier, url);
         } catch (Exception e) {
@@ -210,7 +219,8 @@ public class RemoteWritableMetadataService extends BaseWritableMetadataService i
         return true;
     }
 
-    boolean throwableAction(BiConsumer<SubscriberMetadataIdentifier, Set<String>> consumer, SubscriberMetadataIdentifier metadataIdentifier, Set<String> urls) {
+    boolean throwableAction(BiConsumer<SubscriberMetadataIdentifier, Set<String>> consumer,
+                            SubscriberMetadataIdentifier metadataIdentifier, Set<String> urls) {
         try {
             consumer.accept(metadataIdentifier, urls);
         } catch (Exception e) {
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java
index f46bf21..eed9e43 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java
@@ -1,6 +1,7 @@
 package org.apache.dubbo.metadata.store;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.InmemoryConfiguration;
 import org.apache.dubbo.metadata.WritableMetadataService;
 
 import java.util.SortedSet;
@@ -12,12 +13,12 @@ import java.util.function.BiFunction;
  * @since 2.7.5
  */
 public class RemoteWritableMetadataServiceDelegate implements WritableMetadataService {
-    private WritableMetadataService defaultWritableMetadataService;
-    private RemoteWritableMetadataService remoteWritableMetadataService;
+    InMemoryWritableMetadataService defaultWritableMetadataService;
+    RemoteWritableMetadataService remoteWritableMetadataService;
 
     public RemoteWritableMetadataServiceDelegate() {
-        defaultWritableMetadataService = WritableMetadataService.getDefaultExtension();
-        remoteWritableMetadataService = new RemoteWritableMetadataService();
+        defaultWritableMetadataService = (InMemoryWritableMetadataService) WritableMetadataService.getExtension("local");
+        remoteWritableMetadataService = new RemoteWritableMetadataService(defaultWritableMetadataService);
     }
 
     private WritableMetadataService getDefaultWritableMetadataService() {
@@ -79,9 +80,6 @@ public class RemoteWritableMetadataServiceDelegate implements WritableMetadataSe
     }
 
     private boolean doFunction(BiFunction<WritableMetadataService, URL, Boolean> func, URL url) {
-        boolean result = true;
-        result &= func.apply(defaultWritableMetadataService, url);
-        result &= func.apply(remoteWritableMetadataService, url);
-        return result;
+        return func.apply(defaultWritableMetadataService, url) && func.apply(remoteWritableMetadataService, url);
     }
 }
diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java
new file mode 100644
index 0000000..c032843
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java
@@ -0,0 +1,79 @@
+package org.apache.dubbo.metadata.store;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.metadata.report.MetadataReportInstance;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * 2019-08-29
+ */
+public class InMemoryWritableMetadataServiceTest {
+
+    String interfaceName = "org.apache.dubbo.metadata.store.InterfaceNameTestService2", version = "0.9.9", group = null;
+    URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/?interface=" + interfaceName + "&version="
+            + version + "&application=vicpubprovder&side=provider");
+
+    @BeforeEach
+    public void before() {
+    }
+
+    @Test
+    public void testPublishServiceDefinition() {
+        InMemoryWritableMetadataService inMemoryWritableMetadataService = new InMemoryWritableMetadataService();
+        inMemoryWritableMetadataService.publishServiceDefinition(url);
+
+        String v = inMemoryWritableMetadataService.getServiceDefinition(interfaceName, version, group);
+        Assertions.assertNotNull(v);
+    }
+
+    @Test
+    public void testExportURL() {
+        InMemoryWritableMetadataService inMemoryWritableMetadataService = new InMemoryWritableMetadataService();
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test567Service?version=1.0.44&application=vicpubprovder&side=provider");
+        inMemoryWritableMetadataService.exportURL(url);
+
+        Assertions.assertTrue(inMemoryWritableMetadataService.exportedServiceURLs.size() == 1);
+        Assertions.assertEquals(inMemoryWritableMetadataService.exportedServiceURLs.get(url.getServiceKey()).first(), url);
+    }
+
+    @Test
+    public void testSubscribeURL() {
+        InMemoryWritableMetadataService inMemoryWritableMetadataService = new InMemoryWritableMetadataService();
+        URL url = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test678Service?version=1.0.44&application=vicpubprovder&side=provider");
+        inMemoryWritableMetadataService.subscribeURL(url);
+
+        Assertions.assertTrue(inMemoryWritableMetadataService.subscribedServiceURLs.size() == 1);
+        Assertions.assertEquals(inMemoryWritableMetadataService.subscribedServiceURLs.get(url.getServiceKey()).first(), url);
+    }
+
+    @Test
+    public void testUnExportURL() {
+        InMemoryWritableMetadataService inMemoryWritableMetadataService = new InMemoryWritableMetadataService();
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test567Service?version=1.0.44&application=vicpubprovder&side=provider");
+        inMemoryWritableMetadataService.exportURL(url);
+
+        Assertions.assertTrue(inMemoryWritableMetadataService.exportedServiceURLs.size() == 1);
+        Assertions.assertEquals(inMemoryWritableMetadataService.exportedServiceURLs.get(url.getServiceKey()).first(), url);
+
+        inMemoryWritableMetadataService.unexportURL(url);
+        Assertions.assertTrue(inMemoryWritableMetadataService.exportedServiceURLs.size() == 0);
+    }
+
+    @Test
+    public void testUnSubscribeURL() {
+        InMemoryWritableMetadataService inMemoryWritableMetadataService = new InMemoryWritableMetadataService();
+        URL url = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test678Service?version=1.0.44&application=vicpubprovder&side=provider");
+        inMemoryWritableMetadataService.subscribeURL(url);
+
+        Assertions.assertTrue(inMemoryWritableMetadataService.subscribedServiceURLs.size() == 1);
+        Assertions.assertEquals(inMemoryWritableMetadataService.subscribedServiceURLs.get(url.getServiceKey()).first(), url);
+
+        inMemoryWritableMetadataService.unsubscribeURL(url);
+        Assertions.assertTrue(inMemoryWritableMetadataService.subscribedServiceURLs.size() == 0);
+    }
+
+}
diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java
index fe2b4f6..beeb1bd 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java
@@ -21,7 +21,11 @@ import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.metadata.WritableMetadataService;
 import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
 import org.apache.dubbo.metadata.report.MetadataReportInstance;
+import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;
+import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
+import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
 import org.apache.dubbo.metadata.test.JTestMetadataReport4Test;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 
 import com.google.gson.Gson;
 import org.junit.jupiter.api.Assertions;
@@ -38,24 +42,17 @@ import static org.apache.dubbo.common.constants.CommonConstants.METADATA_REMOTE;
 public class RemoteWritableMeatadataServiceTest {
     URL url = URL.valueOf("JTest://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
     RemoteWritableMetadataService metadataReportService1;
+    InMemoryWritableMetadataService inMemoryWritableMetadataService;
 
     @BeforeEach
     public void before() {
-        metadataReportService1 = (RemoteWritableMetadataService) WritableMetadataService.getExtension(METADATA_REMOTE);
+        inMemoryWritableMetadataService = new InMemoryWritableMetadataService();
+        metadataReportService1 = new RemoteWritableMetadataService(inMemoryWritableMetadataService);
         MetadataReportInstance.init(url);
     }
 
     @Test
-    public void testInstance() {
-
-        RemoteWritableMetadataService metadataReportService2 = (RemoteWritableMetadataService) WritableMetadataService.getExtension(METADATA_REMOTE);
-        Assertions.assertSame(metadataReportService1, metadataReportService2);
-    }
-
-    @Test
     public void testPublishProviderNoInterfaceName() {
-
-
         URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vicpubprovder&side=provider");
         metadataReportService1.publishProvider(publishUrl);
 
@@ -93,7 +90,7 @@ public class RemoteWritableMeatadataServiceTest {
 
         String value = jTestMetadataReport4Test.store.get(JTestMetadataReport4Test.getProviderKey(publishUrl));
         FullServiceDefinition fullServiceDefinition = toServiceDefinition(value);
-        Map<String,String> map = fullServiceDefinition.getParameters();
+        Map<String, String> map = fullServiceDefinition.getParameters();
         Assertions.assertEquals(map.get("application"), "vicpubp");
         Assertions.assertEquals(map.get("version"), "1.0.3");
         Assertions.assertEquals(map.get("interface"), "org.apache.dubbo.metadata.store.InterfaceNameTestService");
@@ -119,6 +116,75 @@ public class RemoteWritableMeatadataServiceTest {
 
     }
 
+    @Test
+    public void testPublishServiceDefinition() {
+        URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vicpubprovder&side=provider");
+        metadataReportService1.publishServiceDefinition(publishUrl);
+
+        Assertions.assertTrue(metadataReportService1.getMetadataReport() instanceof JTestMetadataReport4Test);
+
+        JTestMetadataReport4Test jTestMetadataReport4Test = (JTestMetadataReport4Test) metadataReportService1.getMetadataReport();
+        Assertions.assertTrue(!jTestMetadataReport4Test.store.containsKey(JTestMetadataReport4Test.getProviderKey(publishUrl)));
+
+    }
+
+    @Test
+    public void testUnexportURL() {
+
+    }
+
+    @Test
+    public void testRefreshMetadataService() throws InterruptedException {
+        URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadataService?version=1.0.8&application=vicpubprovder&side=provider");
+        URL publishUrl2 = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata2Service?version=1.0.5&application=vicpubprovder&side=provider");
+        inMemoryWritableMetadataService.exportURL(publishUrl);
+        inMemoryWritableMetadataService.exportURL(publishUrl2);
+        String exportedRevision = "9999";
+        JTestMetadataReport4Test jTestMetadataReport4Test = (JTestMetadataReport4Test) metadataReportService1.getMetadataReport();
+        int origSize = jTestMetadataReport4Test.store.size();
+        Assertions.assertTrue(metadataReportService1.refreshMetadata(exportedRevision, "1109"));
+        Thread.sleep(200);
+        int size = jTestMetadataReport4Test.store.size();
+        Assertions.assertTrue(size - origSize == 2);
+        Assertions.assertEquals(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)), publishUrl.toFullString());
+        Assertions.assertEquals(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl2, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)), publishUrl2.toFullString());
+    }
+
+    @Test
+    public void testRefreshMetadataSubscription() throws InterruptedException {
+        URL subscriberUrl1 = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata00Service?version=1.0.8&application=vicpubprovder&side=provider");
+        URL subscriberUrl2 = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata09Service?version=1.0.5&application=vicpubprovder&side=provider");
+        inMemoryWritableMetadataService.subscribeURL(subscriberUrl1);
+        inMemoryWritableMetadataService.subscribeURL(subscriberUrl2);
+        String exportedRevision = "9999";
+        String subscriberRevision = "2099";
+        String applicationName = "wriableMetadataService";
+        JTestMetadataReport4Test jTestMetadataReport4Test = (JTestMetadataReport4Test) metadataReportService1.getMetadataReport();
+        int origSize = jTestMetadataReport4Test.store.size();
+        ApplicationModel.setApplication(applicationName);
+        Assertions.assertTrue(metadataReportService1.refreshMetadata(exportedRevision, subscriberRevision));
+        Thread.sleep(200);
+        int size = jTestMetadataReport4Test.store.size();
+        Assertions.assertTrue(size - origSize == 1);
+        String r = jTestMetadataReport4Test.store.get(getSubscriberMetadataIdentifier(
+                subscriberRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY));
+        Assertions.assertNotNull(r);
+    }
+
+    private ServiceMetadataIdentifier getServiceMetadataIdentifier(URL publishUrl, String exportedRevision) {
+        ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(publishUrl);
+        serviceMetadataIdentifier.setRevision(exportedRevision);
+        serviceMetadataIdentifier.setProtocol(publishUrl.getProtocol());
+        return serviceMetadataIdentifier;
+    }
+
+    private SubscriberMetadataIdentifier getSubscriberMetadataIdentifier(String subscriberRevision) {
+        SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier();
+        subscriberMetadataIdentifier.setRevision(subscriberRevision);
+        subscriberMetadataIdentifier.setApplication(ApplicationModel.getApplication());
+        return subscriberMetadataIdentifier;
+    }
+
     private FullServiceDefinition toServiceDefinition(String urlQuery) {
         Gson gson = new Gson();
         return gson.fromJson(urlQuery, FullServiceDefinition.class);
diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegateTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegateTest.java
new file mode 100644
index 0000000..10b3eec
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegateTest.java
@@ -0,0 +1,183 @@
+package org.apache.dubbo.metadata.store;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.metadata.WritableMetadataService;
+import org.apache.dubbo.metadata.report.MetadataReportInstance;
+import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;
+import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
+import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
+import org.apache.dubbo.metadata.test.JTestMetadataReport4Test;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.SortedSet;
+
+import static org.apache.dubbo.common.constants.CommonConstants.METADATA_REMOTE;
+
+/**
+ * 2019-08-27
+ */
+public class RemoteWritableMetadataServiceDelegateTest {
+    static URL metadataURL = URL.valueOf("JTest://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Tes33tService?version=1.0.0&application=vic");
+
+    RemoteWritableMetadataServiceDelegate metadataReportService;
+
+    String interfaceName = "org.apache.dubbo.metadata.store.InterfaceNameTestService80", version = "0.6.9", group = null;
+    URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/?interface=" + interfaceName + "&version="
+            + version + "&application=vicpubprovder&side=provider");
+
+    @BeforeAll
+    public static void beforeAll() {
+        MetadataReportInstance.init(metadataURL);
+    }
+
+    @BeforeEach
+    public void before() {
+        metadataReportService = new RemoteWritableMetadataServiceDelegate();
+    }
+
+
+    @Test
+    public void testInstance() {
+        WritableMetadataService metadataReportService1 = WritableMetadataService.getExtension(METADATA_REMOTE);
+        WritableMetadataService metadataReportService2 = WritableMetadataService.getExtension(METADATA_REMOTE);
+        Assertions.assertSame(metadataReportService1, metadataReportService2);
+        Assertions.assertTrue(metadataReportService1 instanceof RemoteWritableMetadataServiceDelegate);
+    }
+
+    @Test
+    public void testPublishServiceDefinition() throws InterruptedException {
+        String interfaceName = "org.apache.dubbo.metadata.store.InterfaceNameTestService2", version = "0.9.9", group = null;
+        URL tmpUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/?interface=" + interfaceName + "&version="
+                + version + "&application=vicpubprovder&side=provider");
+        metadataReportService.publishServiceDefinition(tmpUrl);
+        Thread.sleep(150);
+        String v = metadataReportService.getServiceDefinition(interfaceName, version, group);
+        Assertions.assertNotNull(v);
+    }
+
+    @Test
+    public void testExportURL() throws InterruptedException {
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test567Service?version=1.0.44&application=vicpubprovder&side=provider");
+        metadataReportService.exportURL(url);
+        Thread.sleep(100);
+        Assertions.assertTrue(getInMemoryWriableMetadataService().exportedServiceURLs.size() == 1);
+        Assertions.assertEquals(getInMemoryWriableMetadataService().exportedServiceURLs.get(url.getServiceKey()).first(), url);
+    }
+
+    @Test
+    public void testSubscribeURL() throws InterruptedException {
+        URL url = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test0678Service?version=1.3.144&application=vicpubprovder&side=provider");
+        int origSize = getInMemoryWriableMetadataService().subscribedServiceURLs.size();
+        metadataReportService.subscribeURL(url);
+        Thread.sleep(100);
+        int size = getInMemoryWriableMetadataService().subscribedServiceURLs.size();
+        Assertions.assertTrue(size - origSize == 1);
+        Assertions.assertEquals(getInMemoryWriableMetadataService().subscribedServiceURLs.get(url.getServiceKey()).first(), url);
+    }
+
+    @Test
+    public void testUnExportURL() throws InterruptedException {
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test0567Service?version=1.2.44&application=vicpubprovder&side=provider");
+        int origSize = getInMemoryWriableMetadataService().exportedServiceURLs.size();
+        metadataReportService.exportURL(url);
+        Thread.sleep(100);
+        int size = getInMemoryWriableMetadataService().exportedServiceURLs.size();
+        Assertions.assertTrue(size - origSize == 1);
+        Assertions.assertEquals(getInMemoryWriableMetadataService().exportedServiceURLs.get(url.getServiceKey()).first(), url);
+
+        metadataReportService.unexportURL(url);
+        int unexportSize = getInMemoryWriableMetadataService().exportedServiceURLs.size();
+        Assertions.assertTrue(size - unexportSize == 1);
+    }
+
+    @Test
+    public void testUnSubscribeURL() throws InterruptedException {
+        URL url = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test0678Service?version=1.5.477&application=vicpubprovder&side=provider");
+        int origSize = getInMemoryWriableMetadataService().subscribedServiceURLs.size();
+        metadataReportService.subscribeURL(url);
+        Thread.sleep(100);
+        int size = getInMemoryWriableMetadataService().subscribedServiceURLs.size();
+        Assertions.assertTrue(size - origSize == 1);
+        Assertions.assertEquals(getInMemoryWriableMetadataService().subscribedServiceURLs.get(url.getServiceKey()).first(), url);
+
+        metadataReportService.unsubscribeURL(url);
+        Thread.sleep(100);
+        Assertions.assertTrue(getInMemoryWriableMetadataService().subscribedServiceURLs.size() == 0);
+    }
+
+    @Test
+    public void testRefreshMetadataService() throws InterruptedException {
+        URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadataService?version=1.6.8&application=vicpubprovder&side=provider");
+        URL publishUrl2 = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata2Service?version=1.6.5&application=vicpubprovder&side=provider");
+        metadataReportService.exportURL(publishUrl);
+        metadataReportService.exportURL(publishUrl2);
+        String exportedRevision = "9999";
+        JTestMetadataReport4Test jTestMetadataReport4Test = (JTestMetadataReport4Test) MetadataReportInstance.getMetadataReport(true);
+        int origSize = jTestMetadataReport4Test.store.size();
+        int num = countNum();
+        Assertions.assertTrue(metadataReportService.refreshMetadata(exportedRevision, "1109"));
+        Thread.sleep(200);
+        int size = jTestMetadataReport4Test.store.size();
+        Assertions.assertTrue(size - origSize == num);
+        Assertions.assertEquals(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)), publishUrl.toFullString());
+        Assertions.assertEquals(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl2, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)), publishUrl2.toFullString());
+    }
+
+
+    @Test
+    public void testRefreshMetadataSubscription() throws InterruptedException {
+        URL subscriberUrl1 = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata00Service?version=2.0.8&application=vicpubprovder&side=provider");
+        URL subscriberUrl2 = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata09Service?version=2.0.5&application=vicpubprovder&side=provider");
+        metadataReportService.subscribeURL(subscriberUrl1);
+        metadataReportService.subscribeURL(subscriberUrl2);
+        String exportedRevision = "9999";
+        String subscriberRevision = "2099";
+        String applicationName = "wriableMetadataService";
+        JTestMetadataReport4Test jTestMetadataReport4Test = (JTestMetadataReport4Test) MetadataReportInstance.getMetadataReport(true);
+        int origSize = jTestMetadataReport4Test.store.size();
+        ApplicationModel.setApplication(applicationName);
+        Assertions.assertTrue(metadataReportService.refreshMetadata(exportedRevision, subscriberRevision));
+        Thread.sleep(200);
+        int size = jTestMetadataReport4Test.store.size();
+        Assertions.assertTrue(size - origSize == 1);
+        String r = jTestMetadataReport4Test.store.get(getSubscriberMetadataIdentifier(
+                subscriberRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY));
+        Assertions.assertNotNull(r);
+    }
+
+
+    private ServiceMetadataIdentifier getServiceMetadataIdentifier(URL publishUrl, String exportedRevision) {
+        ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(publishUrl);
+        serviceMetadataIdentifier.setRevision(exportedRevision);
+        serviceMetadataIdentifier.setProtocol(publishUrl.getProtocol());
+        return serviceMetadataIdentifier;
+    }
+
+    private SubscriberMetadataIdentifier getSubscriberMetadataIdentifier(String subscriberRevision) {
+        SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier();
+        subscriberMetadataIdentifier.setRevision(subscriberRevision);
+        subscriberMetadataIdentifier.setApplication(ApplicationModel.getApplication());
+        return subscriberMetadataIdentifier;
+    }
+
+    private InMemoryWritableMetadataService getInMemoryWriableMetadataService() {
+        return (InMemoryWritableMetadataService) metadataReportService.defaultWritableMetadataService;
+    }
+
+    private int countNum() {
+        int num = 0;
+        for (SortedSet<URL> tmp : getInMemoryWriableMetadataService().exportedServiceURLs.values()) {
+            num += tmp.size();
+        }
+        if (!getInMemoryWriableMetadataService().subscribedServiceURLs.values().isEmpty()) {
+            num++;
+        }
+        return num;
+    }
+}
diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReport4Test.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReport4Test.java
index dc1571f..34ebce3 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReport4Test.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReport4Test.java
@@ -25,6 +25,7 @@ import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
 import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
 import org.apache.dubbo.metadata.report.support.AbstractMetadataReport;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -43,7 +44,7 @@ public class JTestMetadataReport4Test extends AbstractMetadataReport {
         super(url);
     }
 
-    public Map<String, String> store = new ConcurrentHashMap<>();
+    public volatile Map<String, String> store = new ConcurrentHashMap<>();
 
 
     private static String getProtocol(URL url) {
@@ -64,22 +65,22 @@ public class JTestMetadataReport4Test extends AbstractMetadataReport {
 
     @Override
     protected void doSaveMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {
-        throw new UnsupportedOperationException("This extension does not support working as a remote metadata center.");
+        store.put(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), url.toFullString());
     }
 
     @Override
     protected void doRemoveMetadata(ServiceMetadataIdentifier metadataIdentifier) {
-        throw new UnsupportedOperationException("This extension does not support working as a remote metadata center.");
+        store.remove(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));
     }
 
     @Override
     protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {
-        throw new UnsupportedOperationException("This extension does not support working as a remote metadata center.");
+        return Arrays.asList(store.getOrDefault(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), ""));
     }
 
     @Override
     protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urls) {
-
+        store.put(subscriberMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), urls);
     }
 
     @Override
@@ -97,6 +98,6 @@ public class JTestMetadataReport4Test extends AbstractMetadataReport {
 
     @Override
     public String getServiceDefinition(MetadataIdentifier consumerMetadataIdentifier) {
-        return null;
+        return store.get(consumerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));
     }
 }