You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2021/01/13 06:26:03 UTC

[dubbo] branch master updated: [Enhancement] Improve code coverage and fix some code (#6197)

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

liujun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/master by this push:
     new bd43fa7  [Enhancement] Improve code coverage and fix some code (#6197)
bd43fa7 is described below

commit bd43fa7fe46d8ac09109c8b83c0e2950dfb919f3
Author: Albumen Kevin <jh...@gmail.com>
AuthorDate: Wed Jan 13 14:25:18 2021 +0800

    [Enhancement] Improve code coverage and fix some code (#6197)
---
 .../apache/dubbo/common/BaseServiceMetadata.java   |   6 +-
 .../java/org/apache/dubbo/common/URLStrParser.java |   2 +-
 .../common/threadpool/ThreadlessExecutor.java      |  27 ++-
 .../dubbo/common/BaseServiceMetadataTest.java      |  65 ++++++++
 .../org/apache/dubbo/common/URLStrParserTest.java  |  58 ++++++-
 .../common/threadpool/ThreadlessExecutorTest.java  |  58 +++++++
 .../threadpool/manager/ExecutorRepositoryTest.java |  79 +++++++++
 .../dubbo/common/timer/HashedWheelTimerTest.java   | 181 +++++++++++++++++----
 .../apache/dubbo/common/utils/DefaultPageTest.java |   9 +-
 .../org/apache/dubbo/common/utils/LogTest.java     |  55 +++++--
 .../apache/dubbo/common/utils/MemberUtilsTest.java |  12 ++
 .../apache/dubbo/common/utils/MethodUtilsTest.java |  54 ++++++
 .../support/command/StatusTelnetHandler.java       |   4 +-
 .../org/apache/dubbo/remoting/MockTransporter.java |  27 ++-
 .../apache/dubbo/remoting/TransportersTest.java    |  46 ++++++
 .../dubbo/remoting/exchange/ExchangersTest.java    |  58 +++++++
 .../dubbo/remoting/exchange/MockExchanger.java     |  31 ++--
 .../dubbo/remoting/telnet/TelnetUtilsTest.java     |  72 ++++++++
 .../telnet/support/ClearTelnetHandlerTest.java     |  46 ++++++
 .../telnet/support/ExitTelnetHandlerTest.java      |  27 +--
 .../telnet/support/HelpTelnetHandlerTest.java      |  48 ++++++
 .../telnet/support/StatusTelnetHandlerTest.java    |  44 +++++
 .../dubbo/remoting/utils/PayloadDropperTest.java   |  43 +++++
 .../apache/dubbo/remoting/utils/UrlUtilsTest.java  |  40 +++++
 .../internal/org.apache.dubbo.remoting.Transporter |   1 +
 .../org.apache.dubbo.remoting.exchange.Exchanger   |   1 +
 26 files changed, 986 insertions(+), 108 deletions(-)

diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/BaseServiceMetadata.java b/dubbo-common/src/main/java/org/apache/dubbo/common/BaseServiceMetadata.java
index 223fc97..9d65ffd 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/BaseServiceMetadata.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/BaseServiceMetadata.java
@@ -22,7 +22,7 @@ import org.apache.dubbo.common.utils.StringUtils;
  * 2019-10-10
  */
 public class BaseServiceMetadata {
-    public static final char COLON_SEPERATOR = ':';
+    public static final char COLON_SEPARATOR = ':';
 
     protected String serviceKey;
     protected String serviceInterfaceName;
@@ -73,7 +73,7 @@ public class BaseServiceMetadata {
     public String getDisplayServiceKey() {
         StringBuilder serviceNameBuilder = new StringBuilder();
         serviceNameBuilder.append(serviceInterfaceName);
-        serviceNameBuilder.append(COLON_SEPERATOR).append(version);
+        serviceNameBuilder.append(COLON_SEPARATOR).append(version);
         return serviceNameBuilder.toString();
     }
 
@@ -84,7 +84,7 @@ public class BaseServiceMetadata {
      * @return
      */
     public static BaseServiceMetadata revertDisplayServiceKey(String displayKey) {
-        String[] eles = StringUtils.split(displayKey, COLON_SEPERATOR);
+        String[] eles = StringUtils.split(displayKey, COLON_SEPARATOR);
         if (eles == null || eles.length < 1 || eles.length > 2) {
             return new BaseServiceMetadata();
         }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java
index 37afb78..2699e48 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java
@@ -159,7 +159,7 @@ public final class URLStrParser {
      */
     public static URL parseEncodedStr(String encodedURLStr) {
         Map<String, String> parameters = null;
-        int pathEndIdx = encodedURLStr.indexOf("%3F");// '?'
+        int pathEndIdx = encodedURLStr.toUpperCase().indexOf("%3F");// '?'
         if (pathEndIdx >= 0) {
             parameters = parseEncodedParams(encodedURLStr, pathEndIdx + 3);
         } else {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadlessExecutor.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadlessExecutor.java
index 0225132..f7faeb6 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadlessExecutor.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadlessExecutor.java
@@ -32,7 +32,7 @@ import java.util.concurrent.TimeoutException;
 /**
  * The most important difference between this Executor and other normal Executor is that this one doesn't manage
  * any thread.
- *
+ * <p>
  * Tasks submitted to this executor through {@link #execute(Runnable)} will not get scheduled to a specific thread, though normal executors always do the schedule.
  * Those tasks are stored in a blocking queue and will only be executed when a thread calls {@link #waitAndDrain()}, the thread executing the task
  * is exactly the same as the one calling waitAndDrain.
@@ -95,12 +95,7 @@ public class ThreadlessExecutor extends AbstractExecutorService {
 
         runnable = queue.poll();
         while (runnable != null) {
-            try {
-                runnable.run();
-            } catch (Throwable t) {
-                logger.info(t);
-
-            }
+            runnable.run();
             runnable = queue.poll();
         }
         // mark the status of ThreadlessExecutor as finished.
@@ -131,6 +126,7 @@ public class ThreadlessExecutor extends AbstractExecutorService {
      */
     @Override
     public void execute(Runnable runnable) {
+        runnable = new RunnableWrapper(runnable);
         synchronized (lock) {
             if (!waiting) {
                 sharedExecutor.execute(runnable);
@@ -180,4 +176,21 @@ public class ThreadlessExecutor extends AbstractExecutorService {
     public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
         return false;
     }
+
+    private static class RunnableWrapper implements Runnable {
+        private Runnable runnable;
+
+        public RunnableWrapper(Runnable runnable) {
+            this.runnable = runnable;
+        }
+
+        @Override
+        public void run() {
+            try {
+                runnable.run();
+            } catch (Throwable t) {
+                logger.info(t);
+            }
+        }
+    }
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/BaseServiceMetadataTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/BaseServiceMetadataTest.java
new file mode 100644
index 0000000..62d860c
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/BaseServiceMetadataTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class BaseServiceMetadataTest {
+
+    @Test
+    public void test() {
+        BaseServiceMetadata baseServiceMetadata = new BaseServiceMetadata();
+        baseServiceMetadata.setGroup("group1");
+        baseServiceMetadata.setServiceInterfaceName("org.apache.dubbo.common.TestInterface");
+        baseServiceMetadata.setVersion("1.0.0");
+        baseServiceMetadata.setServiceKey(BaseServiceMetadata.buildServiceKey("org.apache.dubbo.common.TestInterface", "group1", "1.0.0"));
+
+        assertEquals(baseServiceMetadata.getGroup(), "group1");
+        assertEquals(baseServiceMetadata.getServiceInterfaceName(), "org.apache.dubbo.common.TestInterface");
+        assertEquals(baseServiceMetadata.getVersion(), "1.0.0");
+        assertEquals(baseServiceMetadata.getServiceKey(), "group1/org.apache.dubbo.common.TestInterface:1.0.0");
+        assertEquals(baseServiceMetadata.getDisplayServiceKey(), "org.apache.dubbo.common.TestInterface:1.0.0");
+
+        baseServiceMetadata.setServiceKey(BaseServiceMetadata.buildServiceKey("org.apache.dubbo.common.TestInterface", null, null));
+        assertEquals(baseServiceMetadata.getServiceKey(), "org.apache.dubbo.common.TestInterface");
+        baseServiceMetadata.setServiceKey(BaseServiceMetadata.buildServiceKey("org.apache.dubbo.common.TestInterface", "", ""));
+        assertEquals(baseServiceMetadata.getServiceKey(), "org.apache.dubbo.common.TestInterface");
+
+
+        baseServiceMetadata.setVersion("2.0.0");
+        baseServiceMetadata.generateServiceKey();
+        assertEquals(baseServiceMetadata.getServiceKey(), "group1/org.apache.dubbo.common.TestInterface:2.0.0");
+
+        assertEquals(BaseServiceMetadata.versionFromServiceKey("group1/org.apache.dubbo.common.TestInterface:1.0.0"), "1.0.0");
+        assertEquals(BaseServiceMetadata.groupFromServiceKey("group1/org.apache.dubbo.common.TestInterface:1.0.0"), "group1");
+        assertEquals(BaseServiceMetadata.interfaceFromServiceKey("group1/org.apache.dubbo.common.TestInterface:1.0.0"), "org.apache.dubbo.common.TestInterface");
+
+        assertNull(BaseServiceMetadata.versionFromServiceKey(""));
+        assertNull(BaseServiceMetadata.groupFromServiceKey(""));
+        assertEquals(BaseServiceMetadata.interfaceFromServiceKey(""), "");
+
+        assertEquals(BaseServiceMetadata.revertDisplayServiceKey("org.apache.dubbo.common.TestInterface:1.0.0").getDisplayServiceKey(),
+                "org.apache.dubbo.common.TestInterface:1.0.0");
+        assertEquals(BaseServiceMetadata.revertDisplayServiceKey("org.apache.dubbo.common.TestInterface").getDisplayServiceKey(),
+                "org.apache.dubbo.common.TestInterface:null");
+        assertEquals(BaseServiceMetadata.revertDisplayServiceKey(null).getDisplayServiceKey(),"null:null");
+        assertEquals(BaseServiceMetadata.revertDisplayServiceKey("org.apache.dubbo.common.TestInterface:1.0.0:1").getDisplayServiceKey(),"null:null");
+    }
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/URLStrParserTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/URLStrParserTest.java
index 3ca62ce..f295de9 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/URLStrParserTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/URLStrParserTest.java
@@ -16,8 +16,13 @@
  */
 package org.apache.dubbo.common;
 
+import net.bytebuddy.utility.RandomString;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 
@@ -25,16 +30,53 @@ import static org.hamcrest.MatcherAssert.assertThat;
  * Created by LinShunkang on 2020/03/12
  */
 public class URLStrParserTest {
+    private static Set<String> testCases = new HashSet<>(16);
+    private static Set<String> errorDecodedCases = new HashSet<>(8);
+    private static Set<String> errorEncodedCases = new HashSet<>(8);
+
+    static {
+        testCases.add("dubbo://192.168.1.1");
+        testCases.add("dubbo://192.168.1.1?");
+        testCases.add("dubbo://127.0.0.1?test=中文测试");
+        testCases.add("dubbo://admin:admin123@192.168.1.41:28113/org.test.api.DemoService$Iface?anyhost=true&application=demo-service&dubbo=2.6.1&generic=false&interface=org.test.api.DemoService$Iface&methods=orbCompare,checkText,checkPicture&pid=65557&revision=1.4.17&service.filter=bootMetrics&side=provider&status=server&threads=200&timestamp=1583136298859&version=1.0.0");
+        // super long text test
+        testCases.add("dubbo://192.168.1.1/" + RandomString.make(10240));
+        testCases.add("file:/path/to/file.txt");
+        testCases.add("dubbo://fe80:0:0:0:894:aeec:f37d:23e1%en0/path?abc=abc");
+
+        errorDecodedCases.add("dubbo:192.168.1.1");
+        errorDecodedCases.add("://192.168.1.1");
+        errorDecodedCases.add(":/192.168.1.1");
+
+        errorEncodedCases.add("dubbo%3a%2f%2f192.168.1.41%3fabc%3");
+        errorEncodedCases.add("dubbo%3a192.168.1.1%3fabc%3dabc");
+        errorEncodedCases.add("%3a%2f%2f192.168.1.1%3fabc%3dabc");
+        errorEncodedCases.add("%3a%2f192.168.1.1%3fabc%3dabc");
+        errorEncodedCases.add("dubbo%3a%2f%2f127.0.0.1%3ftest%3d%e2%96%b2%e2%96%bc%e2%97%80%e2%96%b6%e2%86%90%e2%86%91%e2%86%92%e2%86%93%e2%86%94%e2%86%95%e2%88%9e%c2%b1%e9%be%98%e9%9d%90%e9%bd%89%9%d%b");
+    }
 
     @Test
-    public void test() {
-        String str = "dubbo%3A%2F%2Fadmin%3Aadmin123%40192.168.1.41%3A28113%2Forg.test.api.DemoService%24Iface%3Fanyhost%3Dtrue%26application%3Ddemo-service%26dubbo%3D2.6.1%26generic%3Dfalse%26interface%3Dorg.test.api.DemoService%24Iface%26methods%3DorbCompare%2CcheckText%2CcheckPicture%26pid%3D65557%26revision%3D1.4.17%26service.filter%3DbootMetrics%26side%3Dprovider%26status%3Dserver%26threads%3D200%26timestamp%3D1583136298859%26version%3D1.0.0";
-        System.out.println(URLStrParser.parseEncodedStr(str));
-
-        String decodeStr = URL.decode(str);
-        URL originalUrl = URL.valueOf(decodeStr);
-        assertThat(URLStrParser.parseEncodedStr(str), equalTo(originalUrl));
-        assertThat(URLStrParser.parseDecodedStr(decodeStr), equalTo(originalUrl));
+    public void testEncoded() {
+        testCases.forEach(testCase -> {
+            assertThat(URLStrParser.parseEncodedStr(URL.encode(testCase)), equalTo(URL.valueOf(testCase)));
+        });
+
+        errorEncodedCases.forEach(errorCase -> {
+            Assertions.assertThrows(RuntimeException.class,
+                    () -> URLStrParser.parseEncodedStr(errorCase));
+        });
+    }
+
+    @Test
+    public void testDecoded() {
+        testCases.forEach(testCase -> {
+            assertThat(URLStrParser.parseDecodedStr(testCase), equalTo(URL.valueOf(testCase)));
+        });
+
+        errorDecodedCases.forEach(errorCase -> {
+            Assertions.assertThrows(RuntimeException.class,
+                    () -> URLStrParser.parseDecodedStr(errorCase));
+        });
     }
 
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/ThreadlessExecutorTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/ThreadlessExecutorTest.java
new file mode 100644
index 0000000..a17b462
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/ThreadlessExecutorTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.threadpool;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+
+public class ThreadlessExecutorTest {
+    private static ThreadlessExecutor executor;
+
+    static {
+        URL url = URL.valueOf("dubbo://127.0.0.1:12345");
+        ExecutorService sharedExecutor =
+                ExtensionLoader.getExtensionLoader(ExecutorRepository.class)
+                        .getDefaultExtension().createExecutorIfAbsent(url);
+        executor = new ThreadlessExecutor(sharedExecutor);
+    }
+
+    @Test
+    public void test() throws InterruptedException {
+        for (int i = 0; i < 10; i++) {
+            executor.execute(()->{throw new RuntimeException("test");});
+        }
+
+        CompletableFuture<Object> stubFuture = new CompletableFuture<>();
+        executor.setWaitingFuture(stubFuture);
+        Assertions.assertEquals(executor.getWaitingFuture(),stubFuture);
+
+        executor.waitAndDrain();
+
+        executor.execute(()->{});
+
+        executor.waitAndDrain();
+
+        executor.shutdown();
+    }
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepositoryTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepositoryTest.java
new file mode 100644
index 0000000..bb3fe4e
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepositoryTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.threadpool.manager;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+
+public class ExecutorRepositoryTest {
+    private ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
+
+    @Test
+    public void testGetExecutor() {
+        testGet(URL.valueOf("dubbo://127.0.0.1:23456"));
+        testGet(URL.valueOf("dubbo://127.0.0.1:23456?side=consumer"));
+
+        Assertions.assertNotNull(executorRepository.getSharedExecutor());
+        Assertions.assertNotNull(executorRepository.getServiceExporterExecutor());
+        executorRepository.nextScheduledExecutor();
+    }
+
+    private void testGet(URL url) {
+        Assertions.assertNull(executorRepository.getExecutor(url));
+
+        ExecutorService executorService = executorRepository.createExecutorIfAbsent(url);
+        executorService.shutdown();
+        executorService = executorRepository.createExecutorIfAbsent(url);
+        Assertions.assertFalse(executorService.isShutdown());
+
+        Assertions.assertEquals(executorService, executorRepository.getExecutor(url));
+        executorService.shutdown();
+        Assertions.assertNotEquals(executorService, executorRepository.getExecutor(url));
+    }
+
+    @Test
+    public void testUpdateExecutor() {
+        URL url = URL.valueOf("dubbo://127.0.0.1:23456?threads=5");
+        ThreadPoolExecutor executorService = (ThreadPoolExecutor) executorRepository.createExecutorIfAbsent(url);
+
+        executorService.setCorePoolSize(3);
+        executorRepository.updateThreadpool(url, executorService);
+
+        executorService.setCorePoolSize(3);
+        executorService.setMaximumPoolSize(3);
+        executorRepository.updateThreadpool(url, executorService);
+
+        executorService.setMaximumPoolSize(20);
+        executorService.setCorePoolSize(10);
+        executorRepository.updateThreadpool(url, executorService);
+
+        executorService.setCorePoolSize(10);
+        executorService.setMaximumPoolSize(10);
+        executorRepository.updateThreadpool(url, executorService);
+
+        executorService.setCorePoolSize(5);
+        executorRepository.updateThreadpool(url, executorService);
+
+
+    }
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/timer/HashedWheelTimerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/timer/HashedWheelTimerTest.java
index 0223514..6e03fab 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/timer/HashedWheelTimerTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/timer/HashedWheelTimerTest.java
@@ -18,55 +18,180 @@
 package org.apache.dubbo.common.timer;
 
 import org.apache.dubbo.common.utils.NamedThreadFactory;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
+import java.lang.ref.WeakReference;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 public class HashedWheelTimerTest {
+    private CountDownLatch tryStopTaskCountDownLatch = new CountDownLatch(1);
+    private CountDownLatch errorTaskCountDownLatch = new CountDownLatch(1);
 
-    private class PrintTask implements TimerTask {
+    private static class EmptyTask implements TimerTask {
+        @Override
+        public void run(Timeout timeout) {
+        }
+    }
+
+    private static class BlockTask implements TimerTask {
+        @Override
+        public void run(Timeout timeout) throws InterruptedException {
+            this.wait();
+        }
+    }
+
+    private class ErrorTask implements TimerTask {
+        @Override
+        public void run(Timeout timeout) {
+            errorTaskCountDownLatch.countDown();
+            throw new RuntimeException("Test");
+        }
+    }
+
+    private class TryStopTask implements TimerTask {
+        private Timer timer;
+
+        public TryStopTask(Timer timer) {
+            this.timer = timer;
+        }
 
         @Override
         public void run(Timeout timeout) {
-            final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-            System.out.println("task :" + LocalDateTime.now().format(formatter));
+            Assertions.assertThrows(RuntimeException.class, () -> timer.stop());
+            tryStopTaskCountDownLatch.countDown();
         }
     }
 
     @Test
-    public void newTimeout() throws InterruptedException {
-        final Timer timer = newTimer();
-        for (int i = 0; i < 10; i++) {
-            timer.newTimeout(new PrintTask(), 1, TimeUnit.SECONDS);
-            Thread.sleep(1000);
+    public void constructorTest() {
+        // use weak reference to let gc work every time
+        // which can check finalize method and reduce memory usage in time
+        WeakReference<Timer> timer = new WeakReference<>(new HashedWheelTimer());
+        timer = new WeakReference<>(new HashedWheelTimer(100, TimeUnit.MILLISECONDS));
+        timer = new WeakReference<>(new HashedWheelTimer(100, TimeUnit.MILLISECONDS, 8));
+
+        // to cover arg check branches
+        Assertions.assertThrows(RuntimeException.class, () -> {
+            new HashedWheelTimer(
+                    null,
+                    100,
+                    TimeUnit.MILLISECONDS,
+                    8, -1);
+        });
+
+        Assertions.assertThrows(RuntimeException.class, () -> {
+            new HashedWheelTimer(
+                    new NamedThreadFactory("dubbo-future-timeout", true),
+                    0,
+                    TimeUnit.MILLISECONDS,
+                    8, -1);
+        });
+
+        Assertions.assertThrows(RuntimeException.class, () -> {
+            new HashedWheelTimer(
+                    new NamedThreadFactory("dubbo-future-timeout", true),
+                    100,
+                    null,
+                    8, -1);
+        });
+
+        Assertions.assertThrows(RuntimeException.class, () -> {
+            new HashedWheelTimer(
+                    new NamedThreadFactory("dubbo-future-timeout", true),
+                    100,
+                    TimeUnit.MILLISECONDS,
+                    0, -1);
+        });
+
+        Assertions.assertThrows(RuntimeException.class, () -> {
+            new HashedWheelTimer(
+                    new NamedThreadFactory("dubbo-future-timeout", true),
+                    Long.MAX_VALUE,
+                    TimeUnit.MILLISECONDS,
+                    8, -1);
+        });
+
+        Assertions.assertThrows(RuntimeException.class, () -> {
+            new HashedWheelTimer(
+                    new NamedThreadFactory("dubbo-future-timeout", true),
+                    100,
+                    TimeUnit.MILLISECONDS,
+                    Integer.MAX_VALUE, -1);
+        });
+
+        for (int i = 0; i < 128; i++) {
+            // to trigger INSTANCE_COUNT_LIMIT
+            timer = new WeakReference<>(new HashedWheelTimer());
         }
-        Thread.sleep(5000);
+
+        System.gc();
     }
 
     @Test
-    public void stop() throws InterruptedException {
-        final Timer timer = newTimer();
-        for (int i = 0; i < 10; i++) {
-            timer.newTimeout(new PrintTask(), 5, TimeUnit.SECONDS);
-            Thread.sleep(100);
+    public void createTaskTest() throws InterruptedException {
+        HashedWheelTimer timer = new HashedWheelTimer(
+                new NamedThreadFactory("dubbo-future-timeout", true),
+                10,
+                TimeUnit.MILLISECONDS,
+                8, 8);
+
+        Assertions.assertThrows(RuntimeException.class,
+                () -> timer.newTimeout(null, 5, TimeUnit.SECONDS));
+        Assertions.assertThrows(RuntimeException.class,
+                () -> timer.newTimeout(new EmptyTask(), 5, null));
+
+        Timeout timeout = timer.newTimeout(new ErrorTask(), 10, TimeUnit.MILLISECONDS);
+        errorTaskCountDownLatch.await();
+        Assertions.assertFalse(timeout.cancel());
+        Assertions.assertFalse(timeout.isCancelled());
+        Assertions.assertNotNull(timeout.toString());
+        Assertions.assertEquals(timeout.timer(), timer);
+
+        timeout = timer.newTimeout(new EmptyTask(), 1000, TimeUnit.SECONDS);
+        timeout.cancel();
+        Assertions.assertTrue(timeout.isCancelled());
+
+        List<Timeout> timeouts = new LinkedList<>();
+        for (; timer.pendingTimeouts() < 8; ) {
+            // to trigger maxPendingTimeouts
+            timeout = timer.newTimeout(new BlockTask(), -1, TimeUnit.MILLISECONDS);
+            timeouts.add(timeout);
+            Assertions.assertNotNull(timeout.toString());
         }
-        //stop timer
+        Assertions.assertEquals(timer.pendingTimeouts(), 8);
+
+        // this will throw an exception because of maxPendingTimeouts
+        Assertions.assertThrows(RuntimeException.class,
+                () -> timer.newTimeout(new BlockTask(), 1, TimeUnit.MILLISECONDS));
+
+        timeout = timeouts.get(2);
+        // wait until the task expired
+        Thread.sleep(100);
+        Assertions.assertTrue(timeout.isExpired());
+
         timer.stop();
+    }
+
+    @Test
+    public void stopTaskTest() throws InterruptedException {
+        Timer timer = new HashedWheelTimer(new NamedThreadFactory("dubbo-future-timeout", true));
+        timer.newTimeout(new TryStopTask(timer), 10, TimeUnit.MILLISECONDS);
+        tryStopTaskCountDownLatch.await();
 
-        try {
-            //this will throw a exception
-            timer.newTimeout(new PrintTask(), 5, TimeUnit.SECONDS);
-        } catch (Exception e) {
-            e.printStackTrace();
+        for (int i = 0; i < 8; i++) {
+            timer.newTimeout(new EmptyTask(), 0, TimeUnit.SECONDS);
         }
-    }
+        // stop timer
+        timer.stop();
+        Assertions.assertTrue(timer.isStop());
+
+        // this will throw an exception
+        Assertions.assertThrows(RuntimeException.class,
+                () -> timer.newTimeout(new EmptyTask(), 5, TimeUnit.SECONDS));
 
-    private Timer newTimer() {
-        return new HashedWheelTimer(
-                new NamedThreadFactory("dubbo-future-timeout", true),
-                100,
-                TimeUnit.MILLISECONDS);
     }
 }
\ No newline at end of file
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
index 36ceb4d..41c0e03 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.dubbo.common.utils;
 
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import java.util.List;
@@ -32,6 +33,12 @@ public class DefaultPageTest {
     @Test
     public void test() {
         List<Integer> data = asList(1, 2, 3, 4, 5);
-        DefaultPage page = new DefaultPage(0, 1, data.subList(0, 1), data.size());
+        DefaultPage<Integer> page = new DefaultPage<>(0, 1, data.subList(0, 1), data.size());
+        Assertions.assertEquals(page.getOffset(), 0);
+        Assertions.assertEquals(page.getPageSize(), 1);
+        Assertions.assertEquals(page.getTotalSize(), data.size());
+        Assertions.assertEquals(page.getData(), data.subList(0, 1));
+        Assertions.assertEquals(page.getTotalPages(), 5);
+        Assertions.assertTrue(page.hasNext());
     }
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LogTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LogTest.java
index 203cadb..39b60ab 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LogTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LogTest.java
@@ -18,39 +18,68 @@
 package org.apache.dubbo.common.utils;
 
 import org.apache.log4j.Level;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
 
 public class LogTest {
     @Test
     public void testLogName() throws Exception {
-        Log log = new Log();
-        log.setLogName("log-name");
-        assertThat(log.getLogName(), equalTo("log-name"));
+        Log log1 = new Log();
+        Log log2 = new Log();
+        Log log3 = new Log();
+        log1.setLogName("log-name");
+        log2.setLogName("log-name");
+        log3.setLogName("log-name-other");
+        assertThat(log1.getLogName(), equalTo("log-name"));
+        Assertions.assertEquals(log1, log2);
+        Assertions.assertEquals(log1.hashCode(), log2.hashCode());
+        Assertions.assertNotEquals(log1, log3);
     }
 
     @Test
     public void testLogLevel() throws Exception {
-        Log log = new Log();
-        log.setLogLevel(Level.ALL);
-        assertThat(log.getLogLevel(), is(Level.ALL));
+        Log log1 = new Log();
+        Log log2 = new Log();
+        Log log3 = new Log();
+        log1.setLogLevel(Level.ALL);
+        log2.setLogLevel(Level.ALL);
+        log3.setLogLevel(Level.DEBUG);
+        assertThat(log1.getLogLevel(), is(Level.ALL));
+        Assertions.assertEquals(log1, log2);
+        Assertions.assertEquals(log1.hashCode(), log2.hashCode());
+        Assertions.assertNotEquals(log1, log3);
     }
 
     @Test
     public void testLogMessage() throws Exception {
-        Log log = new Log();
-        log.setLogMessage("log-message");
-        assertThat(log.getLogMessage(), equalTo("log-message"));
+        Log log1 = new Log();
+        Log log2 = new Log();
+        Log log3 = new Log();
+        log1.setLogMessage("log-message");
+        log2.setLogMessage("log-message");
+        log3.setLogMessage("log-message-other");
+        assertThat(log1.getLogMessage(), equalTo("log-message"));
+        Assertions.assertEquals(log1, log2);
+        Assertions.assertEquals(log1.hashCode(), log2.hashCode());
+        Assertions.assertNotEquals(log1, log3);
     }
 
     @Test
     public void testLogThread() throws Exception {
-        Log log = new Log();
-        log.setLogThread("log-thread");
-        assertThat(log.getLogThread(), equalTo("log-thread"));
+        Log log1 = new Log();
+        Log log2 = new Log();
+        Log log3 = new Log();
+        log1.setLogThread("log-thread");
+        log2.setLogThread("log-thread");
+        log3.setLogThread("log-thread-other");
+        assertThat(log1.getLogThread(), equalTo("log-thread"));
+        Assertions.assertEquals(log1, log2);
+        Assertions.assertEquals(log1.hashCode(), log2.hashCode());
+        Assertions.assertNotEquals(log1, log3);
     }
 
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java
index 051363b..a5a78cc 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java
@@ -18,6 +18,8 @@ package org.apache.dubbo.common.utils;
 
 import org.junit.jupiter.api.Test;
 
+import static org.apache.dubbo.common.utils.MemberUtils.isPrivate;
+import static org.apache.dubbo.common.utils.MemberUtils.isPublic;
 import static org.apache.dubbo.common.utils.MemberUtils.isStatic;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -34,9 +36,19 @@ public class MemberUtilsTest {
 
         assertFalse(isStatic(getClass().getMethod("testIsStatic")));
         assertTrue(isStatic(getClass().getMethod("staticMethod")));
+        assertTrue(isPrivate(getClass().getDeclaredMethod("privateMethod")));
+        assertTrue(isPublic(getClass().getMethod("publicMethod")));
     }
 
     public static void staticMethod() {
 
     }
+
+    private void privateMethod() {
+
+    }
+
+    public void publicMethod() {
+
+    }
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodUtilsTest.java
index 7cb143e..e8eb7f1 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodUtilsTest.java
@@ -21,6 +21,17 @@ import org.junit.jupiter.api.Test;
 
 import java.lang.reflect.Method;
 
+import static org.apache.dubbo.common.utils.MethodUtils.excludedDeclaredClass;
+import static org.apache.dubbo.common.utils.MethodUtils.findMethod;
+import static org.apache.dubbo.common.utils.MethodUtils.findNearestOverriddenMethod;
+import static org.apache.dubbo.common.utils.MethodUtils.findOverriddenMethod;
+import static org.apache.dubbo.common.utils.MethodUtils.getAllDeclaredMethods;
+import static org.apache.dubbo.common.utils.MethodUtils.getAllMethods;
+import static org.apache.dubbo.common.utils.MethodUtils.getDeclaredMethods;
+import static org.apache.dubbo.common.utils.MethodUtils.getMethods;
+import static org.apache.dubbo.common.utils.MethodUtils.invokeMethod;
+import static org.apache.dubbo.common.utils.MethodUtils.overrides;
+
 public class MethodUtilsTest {
 
     @Test
@@ -53,6 +64,38 @@ public class MethodUtilsTest {
         Assertions.assertFalse(MethodUtils.isDeprecated(MethodTestClazz.class.getMethod("getValue")));
     }
 
+    @Test
+    public void testIsMetaMethod() {
+        boolean containMetaMethod = false;
+        for (Method method : MethodTestClazz.class.getMethods()) {
+            if (MethodUtils.isMetaMethod(method)) {
+                containMetaMethod = true;
+            }
+        }
+        Assertions.assertTrue(containMetaMethod);
+    }
+
+    @Test
+    public void testGetMethods() throws NoSuchMethodException {
+        Assertions.assertTrue(getDeclaredMethods(MethodTestClazz.class, excludedDeclaredClass(String.class)).size() > 0);
+        Assertions.assertTrue(getMethods(MethodTestClazz.class).size() > 0);
+        Assertions.assertTrue(getAllDeclaredMethods(MethodTestClazz.class).size() > 0);
+        Assertions.assertTrue(getAllMethods(MethodTestClazz.class).size() > 0);
+        Assertions.assertNotNull(findMethod(MethodTestClazz.class, "getValue"));
+
+        MethodTestClazz methodTestClazz = new MethodTestClazz();
+        invokeMethod(methodTestClazz, "setValue", "Test");
+        Assertions.assertEquals(methodTestClazz.getValue(), "Test");
+
+        Assertions.assertTrue(overrides(MethodOverrideClazz.class.getMethod("get"),
+                MethodTestClazz.class.getMethod("get")));
+        Assertions.assertEquals(findNearestOverriddenMethod(MethodOverrideClazz.class.getMethod("get")),
+                MethodTestClazz.class.getMethod("get"));
+        Assertions.assertEquals(findOverriddenMethod(MethodOverrideClazz.class.getMethod("get"), MethodOverrideClazz.class),
+                MethodTestClazz.class.getMethod("get"));
+
+    }
+
     public class MethodTestClazz {
         private String value;
 
@@ -64,10 +107,21 @@ public class MethodUtilsTest {
             this.value = value;
         }
 
+        public MethodTestClazz get() {
+            return this;
+        }
+
         @Deprecated
         public Boolean deprecatedMethod() {
             return true;
         }
     }
 
+    public class MethodOverrideClazz extends MethodTestClazz {
+        @Override
+        public MethodTestClazz get() {
+            return this;
+        }
+    }
+
 }
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/StatusTelnetHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/StatusTelnetHandler.java
index 978edd8..b64e708 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/StatusTelnetHandler.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/StatusTelnetHandler.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.common.status.Status;
 import org.apache.dubbo.common.status.StatusChecker;
 import org.apache.dubbo.common.status.support.StatusUtils;
 import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.remoting.Channel;
 import org.apache.dubbo.remoting.telnet.TelnetHandler;
 import org.apache.dubbo.remoting.telnet.support.Help;
@@ -81,7 +82,7 @@ public class StatusTelnetHandler implements TelnetHandler {
         }
         String status = channel.getUrl().getParameter("status");
         Map<String, Status> statuses = new HashMap<String, Status>();
-        if (CollectionUtils.isNotEmptyMap(statuses)) {
+        if (StringUtils.isNotEmpty(status)) {
             String[] ss = COMMA_SPLIT_PATTERN.split(status);
             for (String s : ss) {
                 StatusChecker handler = extensionLoader.getExtension(s);
@@ -97,5 +98,4 @@ public class StatusTelnetHandler implements TelnetHandler {
         Status stat = StatusUtils.getSummaryStatus(statuses);
         return String.valueOf(stat.getLevel());
     }
-
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/MockTransporter.java
similarity index 60%
copy from dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
copy to dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/MockTransporter.java
index 36ceb4d..4bdf890 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/MockTransporter.java
@@ -14,24 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.common.utils;
+package org.apache.dubbo.remoting;
 
-import org.junit.jupiter.api.Test;
+import org.apache.dubbo.common.URL;
 
-import java.util.List;
+import org.mockito.Mockito;
 
-import static java.util.Arrays.asList;
+public class MockTransporter implements Transporter {
+    private RemotingServer server = Mockito.mock(RemotingServer.class);
+    private Client client = Mockito.mock(Client.class);
 
-/**
- * {@link DefaultPage}
- *
- * @since 2.7.5
- */
-public class DefaultPageTest {
+    @Override
+    public RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException {
+        return server;
+    }
 
-    @Test
-    public void test() {
-        List<Integer> data = asList(1, 2, 3, 4, 5);
-        DefaultPage page = new DefaultPage(0, 1, data.subList(0, 1), data.size());
+    @Override
+    public Client connect(URL url, ChannelHandler handler) throws RemotingException {
+        return client;
     }
 }
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/TransportersTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/TransportersTest.java
new file mode 100644
index 0000000..8ebe13d
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/TransportersTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.remoting;
+
+import org.apache.dubbo.common.URL;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+public class TransportersTest {
+    private String url = "dubbo://127.0.0.1:12345?transporter=mockTransporter";
+    private ChannelHandler channel = Mockito.mock(ChannelHandler.class);
+
+    @Test
+    public void testBind() throws RemotingException {
+        Assertions.assertThrows(RuntimeException.class, () -> Transporters.bind((String) null));
+        Assertions.assertThrows(RuntimeException.class, () -> Transporters.bind((URL) null));
+        Assertions.assertThrows(RuntimeException.class, () -> Transporters.bind(url));
+        Assertions.assertNotNull(Transporters.bind(url, channel));
+        Assertions.assertNotNull(Transporters.bind(url, channel, channel));
+    }
+
+    @Test
+    public void testConnect() throws RemotingException {
+        Assertions.assertThrows(RuntimeException.class, () -> Transporters.connect((String) null));
+        Assertions.assertThrows(RuntimeException.class, () -> Transporters.connect((URL) null));
+        Assertions.assertNotNull(Transporters.connect(url));
+        Assertions.assertNotNull(Transporters.connect(url, channel));
+        Assertions.assertNotNull(Transporters.connect(url, channel, channel));
+    }
+}
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/ExchangersTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/ExchangersTest.java
new file mode 100644
index 0000000..0306d85
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/ExchangersTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.remoting.exchange;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.RemotingException;
+import org.apache.dubbo.remoting.exchange.support.ExchangeHandlerDispatcher;
+import org.apache.dubbo.remoting.exchange.support.Replier;
+import org.apache.dubbo.remoting.transport.ChannelHandlerAdapter;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+public class ExchangersTest {
+
+    @Test
+    public void testBind() throws RemotingException {
+        String url = "dubbo://127.0.0.1:12345?exchanger=mockExchanger";
+        Exchangers.bind(url, Mockito.mock(Replier.class));
+        Exchangers.bind(url, new ChannelHandlerAdapter(), Mockito.mock(Replier.class));
+        Exchangers.bind(url, new ExchangeHandlerDispatcher());
+
+        Assertions.assertThrows(RuntimeException.class,
+                () -> Exchangers.bind((URL) null, new ExchangeHandlerDispatcher()));
+        Assertions.assertThrows(RuntimeException.class,
+                () -> Exchangers.bind(url, (ExchangeHandlerDispatcher) null));
+    }
+
+    @Test
+    public void testConnect() throws RemotingException {
+        String url = "dubbo://127.0.0.1:12345?exchanger=mockExchanger";
+        Exchangers.connect(url);
+        Exchangers.connect(url, Mockito.mock(Replier.class));
+        Exchangers.connect(URL.valueOf(url), Mockito.mock(Replier.class));
+        Exchangers.connect(url, new ChannelHandlerAdapter(), Mockito.mock(Replier.class));
+        Exchangers.connect(url, new ExchangeHandlerDispatcher());
+
+        Assertions.assertThrows(RuntimeException.class,
+                () -> Exchangers.connect((URL) null, new ExchangeHandlerDispatcher()));
+        Assertions.assertThrows(RuntimeException.class,
+                () -> Exchangers.connect(url, (ExchangeHandlerDispatcher) null));
+    }
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/MockExchanger.java
similarity index 55%
copy from dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java
copy to dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/MockExchanger.java
index 051363b..9c820c0 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/MockExchanger.java
@@ -14,29 +14,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.common.utils;
+package org.apache.dubbo.remoting.exchange;
 
-import org.junit.jupiter.api.Test;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.RemotingException;
 
-import static org.apache.dubbo.common.utils.MemberUtils.isStatic;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.mockito.Mockito;
 
-/**
- * {@link MemberUtils} Test
- *
- * @since 2.7.6
- */
-public class MemberUtilsTest {
+public class MockExchanger implements Exchanger{
+    private ExchangeServer exchangeServer = Mockito.mock(ExchangeServer.class);
+    private ExchangeClient exchangeClient = Mockito.mock(ExchangeClient.class);
 
-    @Test
-    public void testIsStatic() throws NoSuchMethodException {
-
-        assertFalse(isStatic(getClass().getMethod("testIsStatic")));
-        assertTrue(isStatic(getClass().getMethod("staticMethod")));
+    @Override
+    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
+        return exchangeServer;
     }
 
-    public static void staticMethod() {
-
+    @Override
+    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
+        return exchangeClient;
     }
 }
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/TelnetUtilsTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/TelnetUtilsTest.java
new file mode 100644
index 0000000..1822837
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/TelnetUtilsTest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.remoting.telnet;
+
+import org.apache.dubbo.remoting.telnet.support.TelnetUtils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public class TelnetUtilsTest {
+
+    /**
+     * abc - abc - abc
+     * 1   - 2   - 3
+     * x   - y   - z
+     */
+    @Test
+    public void testToList() {
+        List<List<String>> table = new LinkedList<>();
+        table.add(Arrays.asList("abc","abc","abc"));
+        table.add(Arrays.asList("1","2","3"));
+        table.add(Arrays.asList("x","y","z"));
+
+        String toList = TelnetUtils.toList(table);
+
+        Assertions.assertTrue(toList.contains("abc - abc - abc"));
+        Assertions.assertTrue(toList.contains("1   - 2   - 3"));
+        Assertions.assertTrue(toList.contains("x   - y   - z"));
+    }
+
+    /**
+     * +-----+-----+-----+
+     * | A   | B   | C   |
+     * +-----+-----+-----+
+     * | abc | abc | abc |
+     * | 1   | 2   | 3   |
+     * | x   | y   | z   |
+     * +-----+-----+-----+
+     */
+    @Test
+    public void testToTable() {
+        List<List<String>> table = new LinkedList<>();
+        table.add(Arrays.asList("abc","abc","abc"));
+        table.add(Arrays.asList("1","2","3"));
+        table.add(Arrays.asList("x","y","z"));
+
+        String toTable = TelnetUtils.toTable(new String[]{"A","B","C"},table);
+
+        Assertions.assertTrue(toTable.contains("| A   | B   | C   |"));
+        Assertions.assertTrue(toTable.contains("| abc | abc | abc |"));
+        Assertions.assertTrue(toTable.contains("| 1   | 2   | 3   |"));
+        Assertions.assertTrue(toTable.contains("| x   | y   | z   |"));
+    }
+}
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/ClearTelnetHandlerTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/ClearTelnetHandlerTest.java
new file mode 100644
index 0000000..7671ab5
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/ClearTelnetHandlerTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.remoting.telnet.support;
+
+import org.apache.dubbo.remoting.Channel;
+import org.apache.dubbo.remoting.telnet.support.command.ClearTelnetHandler;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+public class ClearTelnetHandlerTest {
+
+    @Test
+    public void test() {
+        StringBuilder buf = new StringBuilder();
+        for (int i = 0; i < 50; i++) {
+            buf.append("\r\n");
+        }
+
+        ClearTelnetHandler telnetHandler = new ClearTelnetHandler();
+        Assertions.assertEquals(buf.toString(), telnetHandler.telnet(Mockito.mock(Channel.class), "50"));
+
+        // Illegal Input
+        Assertions.assertTrue(telnetHandler.telnet(Mockito.mock(Channel.class), "Illegal").contains("Illegal"));
+
+        for (int i = 0; i < 50; i++) {
+            buf.append("\r\n");
+        }
+        Assertions.assertEquals(buf.toString(), telnetHandler.telnet(Mockito.mock(Channel.class), ""));
+    }
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/ExitTelnetHandlerTest.java
similarity index 62%
copy from dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
copy to dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/ExitTelnetHandlerTest.java
index 36ceb4d..470f310 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/ExitTelnetHandlerTest.java
@@ -14,24 +14,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.common.utils;
+package org.apache.dubbo.remoting.telnet.support;
 
-import org.junit.jupiter.api.Test;
+import org.apache.dubbo.remoting.Channel;
+import org.apache.dubbo.remoting.telnet.support.command.ExitTelnetHandler;
 
-import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
 
-import static java.util.Arrays.asList;
-
-/**
- * {@link DefaultPage}
- *
- * @since 2.7.5
- */
-public class DefaultPageTest {
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
+public class ExitTelnetHandlerTest {
     @Test
     public void test() {
-        List<Integer> data = asList(1, 2, 3, 4, 5);
-        DefaultPage page = new DefaultPage(0, 1, data.subList(0, 1), data.size());
+        Channel channel = Mockito.mock(Channel.class);
+
+        ExitTelnetHandler exitTelnetHandler = new ExitTelnetHandler();
+        exitTelnetHandler.telnet(channel, null);
+
+        verify(channel, times(1)).close();
     }
 }
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/HelpTelnetHandlerTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/HelpTelnetHandlerTest.java
new file mode 100644
index 0000000..2f2a10e
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/HelpTelnetHandlerTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.remoting.telnet.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.Channel;
+import org.apache.dubbo.remoting.telnet.support.command.HelpTelnetHandler;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+public class HelpTelnetHandlerTest {
+    @Test
+    public void test() {
+        Channel channel = Mockito.mock(Channel.class);
+        Mockito.when(channel.getUrl()).thenReturn(URL.valueOf("dubbo://127.0.0.1:12345"));
+
+        HelpTelnetHandler helpTelnetHandler = new HelpTelnetHandler();
+        // default output
+        String prompt = "Please input \"help [command]\" show detail.\r\n";
+        Assertions.assertTrue(helpTelnetHandler.telnet(channel, "").contains(prompt));
+
+        // "help" command output
+        String demoOutput =
+                "Command:\r\n" +
+                "    help [command]\r\n" +
+                "Summary:\r\n" +
+                "    Show help.\r\n" +
+                "Detail:\r\n" +
+                "    Show help.";
+        Assertions.assertEquals(helpTelnetHandler.telnet(channel, "help"),demoOutput);
+    }
+}
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/StatusTelnetHandlerTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/StatusTelnetHandlerTest.java
new file mode 100644
index 0000000..56e884d
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/StatusTelnetHandlerTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.remoting.telnet.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.Channel;
+import org.apache.dubbo.remoting.telnet.support.command.StatusTelnetHandler;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+public class StatusTelnetHandlerTest {
+    @Test
+    public void test() {
+        Channel channel = Mockito.mock(Channel.class);
+        Mockito.when(channel.getUrl()).thenReturn(URL.valueOf("dubbo://127.0.0.1:12345"));
+
+        StatusTelnetHandler statusTelnetHandler = new StatusTelnetHandler();
+        Assertions.assertNotNull(statusTelnetHandler.telnet(channel,""));
+        Assertions.assertNotNull(statusTelnetHandler.telnet(channel,"-l"));
+
+        String errorPrompt = "Unsupported parameter ";
+        Assertions.assertTrue(statusTelnetHandler.telnet(channel,"other").contains(errorPrompt));
+
+        Mockito.when(channel.getUrl()).thenReturn(URL.valueOf("dubbo://127.0.0.1:12345?status=load,memory"));
+        Assertions.assertNotNull(statusTelnetHandler.telnet(channel,""));
+        Assertions.assertNotNull(statusTelnetHandler.telnet(channel,"-l"));
+    }
+}
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/utils/PayloadDropperTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/utils/PayloadDropperTest.java
new file mode 100644
index 0000000..0e55032
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/utils/PayloadDropperTest.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.remoting.utils;
+
+import org.apache.dubbo.remoting.exchange.Request;
+import org.apache.dubbo.remoting.exchange.Response;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class PayloadDropperTest {
+    @Test
+    public void test() {
+        Request request = new Request(1);
+        request.setData(new Object());
+        Request requestWithoutData = (Request) PayloadDropper.getRequestWithoutData(request);
+        Assertions.assertEquals(requestWithoutData.getId(), request.getId());
+        Assertions.assertNull(requestWithoutData.getData());
+
+        Response response = new Response(1);
+        response.setResult(new Object());
+        Response responseWithoutData = (Response) PayloadDropper.getRequestWithoutData(response);
+        Assertions.assertEquals(responseWithoutData.getId(), response.getId());
+        Assertions.assertNull(responseWithoutData.getResult());
+
+        Object object = new Object();
+        Assertions.assertEquals(object, PayloadDropper.getRequestWithoutData(object));
+    }
+}
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/utils/UrlUtilsTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/utils/UrlUtilsTest.java
new file mode 100644
index 0000000..7b475ae
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/utils/UrlUtilsTest.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.remoting.utils;
+
+import org.apache.dubbo.common.URL;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class UrlUtilsTest {
+    @Test
+    public void testGetIdleTimeout() {
+        URL url1 = URL.valueOf("dubbo://127.0.0.1:12345?heartbeat=10000");
+        URL url2 = URL.valueOf("dubbo://127.0.0.1:12345?heartbeat=10000&heartbeat.timeout=50000");
+        URL url3 = URL.valueOf("dubbo://127.0.0.1:12345?heartbeat=10000&heartbeat.timeout=10000");
+        Assertions.assertEquals(UrlUtils.getIdleTimeout(url1), 30000);
+        Assertions.assertEquals(UrlUtils.getIdleTimeout(url2), 50000);
+        Assertions.assertThrows(RuntimeException.class, () -> UrlUtils.getIdleTimeout(url3));
+    }
+
+    @Test
+    public void testGetHeartbeat() {
+        URL url = URL.valueOf("dubbo://127.0.0.1:12345?heartbeat=10000");
+        Assertions.assertEquals(UrlUtils.getHeartbeat(url), 10000);
+    }
+}
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter b/dubbo-remoting/dubbo-remoting-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter
new file mode 100644
index 0000000..8c02a4a
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter
@@ -0,0 +1 @@
+mockTransporter = org.apache.dubbo.remoting.MockTransporter
\ No newline at end of file
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger b/dubbo-remoting/dubbo-remoting-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger
new file mode 100644
index 0000000..f5b1c56
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger
@@ -0,0 +1 @@
+mockExchanger = org.apache.dubbo.remoting.exchange.MockExchanger
\ No newline at end of file