You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2022/05/02 10:13:11 UTC

[dubbo-go] branch 3.0 updated: Tst:mock etcd and nacos in ut (#1873)

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

alexstocks pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new 7d4af3b08 Tst:mock etcd and nacos in ut (#1873)
7d4af3b08 is described below

commit 7d4af3b08f1c9fab82819a02b424db41b94489db
Author: pherzheyu <99...@users.noreply.github.com>
AuthorDate: Mon May 2 18:13:05 2022 +0800

    Tst:mock etcd and nacos in ut (#1873)
    
    * godoc (#1755)
    
    * update package comment (#1755)
    
    * imports formatter (#1755)
    
    * filter/graceful_shutdown license (#1755)
    
    * filter/graceful_shutdown license (#1755)
    
    * update some comment (#1755)
    
    * gofmt (#1755)
    
    * Update version.go
    
    comment for blank (#1755)
    
    * comment for blank (#1755)
    
    * comment (#1755)
    
    * ut mock nacos and etcd (#1774)
    
    * mock nacos nolint
    
    * mock etcd nolint
    
    * ut mock update (#1774)
---
 cluster/cluster/zoneaware/cluster_invoker_test.go |   4 +-
 config_center/nacos/impl_test.go                  | 262 +++++++++---
 go.mod                                            |   4 +-
 go.sum                                            |  67 +--
 metadata/report/etcd/report_test.go               | 406 +++++++++++++-----
 metadata/report/nacos/report_test.go              | 489 +++++++++++++++++++---
 registry/etcdv3/listener_test.go                  |  96 ++---
 registry/etcdv3/registry_test.go                  | 170 ++++----
 registry/nacos/registry_test.go                   | 450 ++++++++++++--------
 remoting/etcdv3/listener_test.go                  | 132 +-----
 remoting/nacos/builder_test.go                    | 270 +++++++-----
 11 files changed, 1544 insertions(+), 806 deletions(-)

diff --git a/cluster/cluster/zoneaware/cluster_invoker_test.go b/cluster/cluster/zoneaware/cluster_invoker_test.go
index 705218eb9..a9ae7c95d 100644
--- a/cluster/cluster/zoneaware/cluster_invoker_test.go
+++ b/cluster/cluster/zoneaware/cluster_invoker_test.go
@@ -68,7 +68,7 @@ func TestZoneWareInvokerWithPreferredSuccess(t *testing.T) {
 			invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(
 				func(invocation protocol.Invocation) protocol.Result {
 					return &protocol.RPCResult{}
-				})
+				}).AnyTimes()
 		}
 
 		invokers = append(invokers, invoker)
@@ -166,7 +166,7 @@ func TestZoneWareInvokerWithZoneSuccess(t *testing.T) {
 					Attrs: map[string]interface{}{constant.RegistryZoneKey: zoneValue},
 					Rest:  clusterpkg.Rest{Tried: 0, Success: true},
 				}
-			})
+			}).AnyTimes()
 		invokers = append(invokers, invoker)
 	}
 
diff --git a/config_center/nacos/impl_test.go b/config_center/nacos/impl_test.go
index 2ed505995..209fbaf45 100644
--- a/config_center/nacos/impl_test.go
+++ b/config_center/nacos/impl_test.go
@@ -15,85 +15,253 @@
  * limitations under the License.
  */
 
+// nolint
 package nacos
 
 import (
-	"net/url"
+	"reflect"
 	"sync"
 	"testing"
-	"time"
 )
 
 import (
-	"github.com/stretchr/testify/assert"
+	gxset "github.com/dubbogo/gost/container/set"
+	nacosClient "github.com/dubbogo/gost/database/kv/nacos"
+
+	"github.com/golang/mock/gomock"
+
+	"github.com/nacos-group/nacos-sdk-go/model"
+	"github.com/nacos-group/nacos-sdk-go/vo"
 )
 
 import (
 	"dubbo.apache.org/dubbo-go/v3/common"
-	"dubbo.apache.org/dubbo-go/v3/common/constant"
 	"dubbo.apache.org/dubbo-go/v3/config_center"
 	"dubbo.apache.org/dubbo-go/v3/config_center/parser"
 )
 
-func getNacosConfig(t *testing.T) config_center.DynamicConfiguration {
-	params := url.Values{}
-	params.Set(constant.NacosNotLoadLocalCache, "true")
+// MockIConfigClient is a mock of IConfigClient interface
+type MockIConfigClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockIConfigClientMockRecorder
+}
+
+// MockIConfigClientMockRecorder is the mock recorder for MockIConfigClient
+type MockIConfigClientMockRecorder struct {
+	mock *MockIConfigClient
+}
 
-	params.Set(constant.NacosNamespaceID, "nacos")
-	params.Set(constant.TimeoutKey, "5s")
-	params.Set(constant.ClientNameKey, "nacos-client")
+// NewMockIConfigClient creates a new mock instance
+func NewMockIConfigClient(ctrl *gomock.Controller) *MockIConfigClient {
+	mock := &MockIConfigClient{ctrl: ctrl}
+	mock.recorder = &MockIConfigClientMockRecorder{mock}
+	return mock
+}
 
-	registryUrl, err := common.NewURL("registry://console.nacos.io:80", common.WithParams(params))
-	assert.Nil(t, err)
-	nacosConfig, err := newNacosDynamicConfiguration(registryUrl)
-	assert.Nil(t, err)
-	return nacosConfig
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *MockIConfigClient) EXPECT() *MockIConfigClientMockRecorder {
+	return m.recorder
 }
 
-func TestPublishConfig(t *testing.T) {
-	nacosConfig := getNacosConfig(t)
-	data := `dubbo.protocol.name=dubbo`
-	err := nacosConfig.PublishConfig("dubbo.properties", "dubbo-go", data)
-	assert.Nil(t, err)
+// GetConfig mocks base method
+func (m *MockIConfigClient) GetConfig(param vo.ConfigParam) (string, error) {
+	ret := m.ctrl.Call(m, "GetConfig", param)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
 }
 
-func TestGetConfig(t *testing.T) {
-	nacosConfig := getNacosConfig(t)
-	nacosConfig.SetParser(&parser.DefaultConfigurationParser{})
+// GetConfig indicates an expected call of GetConfig
+func (mr *MockIConfigClientMockRecorder) GetConfig(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfig", reflect.TypeOf((*MockIConfigClient)(nil).GetConfig), param)
+}
 
-	config, err := nacosConfig.GetProperties("dubbo.properties", config_center.WithGroup("dubbo-go"))
-	assert.NotEmpty(t, config)
-	assert.NoError(t, err)
+// PublishConfig mocks base method
+func (m *MockIConfigClient) PublishConfig(param vo.ConfigParam) (bool, error) {
+	ret := m.ctrl.Call(m, "PublishConfig", param)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
 
-	parse, err := nacosConfig.Parser().Parse(config)
-	assert.NoError(t, err)
-	assert.Equal(t, parse["dubbo.protocol.name"], "dubbo")
+// PublishConfig indicates an expected call of PublishConfig
+func (mr *MockIConfigClientMockRecorder) PublishConfig(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishConfig", reflect.TypeOf((*MockIConfigClient)(nil).PublishConfig), param)
 }
 
-func TestGetConfigKeysByGroup(t *testing.T) {
-	nacosConfig := getNacosConfig(t)
-	config, err := nacosConfig.GetConfigKeysByGroup("dubbo-go")
-	assert.NoError(t, err)
-	assert.True(t, config.Contains("dubbo.properties"))
+// DeleteConfig mocks base method
+func (m *MockIConfigClient) DeleteConfig(param vo.ConfigParam) (bool, error) {
+	ret := m.ctrl.Call(m, "DeleteConfig", param)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
 }
 
-func TestAddListener(t *testing.T) {
-	nacosConfig := getNacosConfig(t)
-	listener := &mockDataListener{}
-	time.Sleep(time.Second * 2)
-	nacosConfig.AddListener("dubbo.properties", listener)
+// DeleteConfig indicates an expected call of DeleteConfig
+func (mr *MockIConfigClientMockRecorder) DeleteConfig(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteConfig", reflect.TypeOf((*MockIConfigClient)(nil).DeleteConfig), param)
 }
 
-func TestRemoveListener(_ *testing.T) {
-	// TODO not supported in current go_nacos_sdk version
+// ListenConfig mocks base method
+func (m *MockIConfigClient) ListenConfig(params vo.ConfigParam) error {
+	ret := m.ctrl.Call(m, "ListenConfig", params)
+	ret0, _ := ret[0].(error)
+	return ret0
 }
 
-type mockDataListener struct {
-	wg    sync.WaitGroup
-	event string
+// ListenConfig indicates an expected call of ListenConfig
+func (mr *MockIConfigClientMockRecorder) ListenConfig(params interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListenConfig", reflect.TypeOf((*MockIConfigClient)(nil).ListenConfig), params)
 }
 
-func (l *mockDataListener) Process(configType *config_center.ConfigChangeEvent) {
-	l.wg.Done()
-	l.event = configType.Key
+// CancelListenConfig mocks base method
+func (m *MockIConfigClient) CancelListenConfig(params vo.ConfigParam) error {
+	ret := m.ctrl.Call(m, "CancelListenConfig", params)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// CancelListenConfig indicates an expected call of CancelListenConfig
+func (mr *MockIConfigClientMockRecorder) CancelListenConfig(params interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelListenConfig", reflect.TypeOf((*MockIConfigClient)(nil).CancelListenConfig), params)
+}
+
+// SearchConfig mocks base method
+func (m *MockIConfigClient) SearchConfig(param vo.SearchConfigParam) (*model.ConfigPage, error) {
+	ret := m.ctrl.Call(m, "SearchConfig", param)
+	ret0, _ := ret[0].(*model.ConfigPage)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// SearchConfig indicates an expected call of SearchConfig
+func (mr *MockIConfigClientMockRecorder) SearchConfig(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchConfig", reflect.TypeOf((*MockIConfigClient)(nil).SearchConfig), param)
+}
+
+// PublishAggr mocks base method
+func (m *MockIConfigClient) PublishAggr(param vo.ConfigParam) (bool, error) {
+	ret := m.ctrl.Call(m, "PublishAggr", param)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// PublishAggr indicates an expected call of PublishAggr
+func (mr *MockIConfigClientMockRecorder) PublishAggr(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishAggr", reflect.TypeOf((*MockIConfigClient)(nil).PublishAggr), param)
+}
+
+type fields struct {
+	BaseDynamicConfiguration config_center.BaseDynamicConfiguration
+	url                      *common.URL
+	rootPath                 string
+	wg                       sync.WaitGroup
+	cltLock                  sync.Mutex
+	done                     chan struct{}
+	client                   *nacosClient.NacosConfigClient
+	keyListeners             sync.Map
+	parser                   parser.ConfigurationParser
+}
+type args struct {
+	key   string
+	group string
+	value string
+}
+
+func newnNacosDynamicConfiguration(f fields) *nacosDynamicConfiguration {
+	return &nacosDynamicConfiguration{
+		BaseDynamicConfiguration: f.BaseDynamicConfiguration,
+		url:                      f.url,
+		rootPath:                 f.rootPath,
+		done:                     f.done,
+		client:                   f.client,
+		parser:                   f.parser,
+	}
+}
+
+func Test_nacosDynamicConfiguration_PublishConfig(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().PublishConfig(gomock.Any()).Return(true, nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				key:   "dubbo.properties",
+				group: "dubbogo",
+				value: "dubbo.protocol.name=dubbo",
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newnNacosDynamicConfiguration(tt.fields)
+			if err := n.PublishConfig(tt.args.key, tt.args.group, tt.args.value); (err != nil) != tt.wantErr {
+				t.Errorf("PublishConfig() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_nacosDynamicConfiguration_GetConfigKeysByGroup(t *testing.T) {
+	cp := &model.ConfigPage{
+		PageItems: []model.ConfigItem{
+			{
+				DataId: "dubbogo",
+			},
+		},
+	}
+	result := gxset.NewSet()
+	result.Add("dubbogo")
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().SearchConfig(gomock.Any()).Return(cp, nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    *gxset.HashSet
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				group: "dubbo",
+			},
+			want:    result,
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newnNacosDynamicConfiguration(tt.fields)
+			got, err := n.GetConfigKeysByGroup(tt.args.group)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetConfigKeysByGroup() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("GetConfigKeysByGroup() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
 }
diff --git a/go.mod b/go.mod
index 6b7542613..051901b32 100644
--- a/go.mod
+++ b/go.mod
@@ -7,6 +7,7 @@ require (
 	github.com/RoaringBitmap/roaring v0.7.1
 	github.com/Workiva/go-datastructures v1.0.52
 	github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
+	github.com/agiledragon/gomonkey v2.0.2+incompatible
 	github.com/alibaba/sentinel-golang v1.0.4
 	github.com/apache/dubbo-getty v1.4.8
 	github.com/apache/dubbo-go-hessian2 v1.11.0
@@ -25,7 +26,7 @@ require (
 	github.com/go-co-op/gocron v1.9.0
 	github.com/go-playground/validator/v10 v10.10.1
 	github.com/go-resty/resty/v2 v2.7.0
-	github.com/golang/mock v1.4.4
+	github.com/golang/mock v1.5.0
 	github.com/golang/protobuf v1.5.2
 	github.com/google/go-cmp v0.5.8
 	github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645
@@ -46,7 +47,6 @@ require (
 	github.com/zouyx/agollo/v3 v3.4.5
 	go.etcd.io/etcd/api/v3 v3.5.4
 	go.etcd.io/etcd/client/v3 v3.5.4
-	go.etcd.io/etcd/server/v3 v3.5.4
 	go.uber.org/atomic v1.9.0
 	go.uber.org/zap v1.21.0
 	google.golang.org/genproto v0.0.0-20211104193956-4c6863e31247
diff --git a/go.sum b/go.sum
index 351ed2433..e02c4e527 100644
--- a/go.sum
+++ b/go.sum
@@ -108,7 +108,6 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72H
 github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk=
 github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g=
 github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
-github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
 github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -126,9 +125,8 @@ github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40 h1:xvUo53O5MRZhVMJAxWCJcS5HHrqAiAG9SJ1LpMu6aAI=
 github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
-github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
-github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -238,9 +236,8 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
 github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
-github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
-github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
 github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
 github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
 github.com/frankban/quicktest v1.10.0 h1:Gfh+GAJZOAoKZsIZeZbdn2JF10kN1XHNvjsvQK8gVkE=
@@ -329,8 +326,9 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
 github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
 github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
 github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -347,7 +345,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -362,9 +359,8 @@ github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2
 github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw=
 github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
-github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -415,9 +411,8 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=
 github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -759,9 +754,8 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s
 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5 h1:GJTW+uNMIV1RKwox+T4aN0/sQlYRg78uHZf2H0aBcDw=
 github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
-github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
-github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
 github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
@@ -773,7 +767,6 @@ github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
-github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
 github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -838,9 +831,8 @@ github.com/zouyx/agollo/v3 v3.4.5 h1:7YCxzY9ZYaH9TuVUBvmI6Tk0mwMggikah+cfbYogcHQ
 github.com/zouyx/agollo/v3 v3.4.5/go.mod h1:LJr3kDmm23QSW+F1Ol4TMHDa7HvJvscMdVxJ2IpUTVc=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
 go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
-go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
-go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
 go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0=
 go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
 go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw=
@@ -848,21 +840,17 @@ go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc=
 go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
 go.etcd.io/etcd/client/pkg/v3 v3.5.4 h1:lrneYvz923dvC14R54XcA7FXoZ3mlGZAgmwhfm7HqOg=
 go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/v2 v2.305.0-alpha.0 h1:jZepGpOeJATxsbMNBZczDS2jHdK/QVHM1iPe9jURJ8o=
 go.etcd.io/etcd/client/v2 v2.305.0-alpha.0/go.mod h1:kdV+xzCJ3luEBSIeQyB/OEKkWKd8Zkux4sbDeANrosU=
-go.etcd.io/etcd/client/v2 v2.305.4 h1:Dcx3/MYyfKcPNLpR4VVQUP5KgYrBeJtktBwEKkw08Ao=
-go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU=
 go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8=
 go.etcd.io/etcd/client/v3 v3.5.4 h1:p83BUL3tAYS0OT/r0qglgc3M1JjhM0diV8DSWAhVXv4=
 go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
+go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 h1:3yLUEC0nFCxw/RArImOyRUI4OAFbg4PFpBbAhSNzKNY=
 go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY=
-go.etcd.io/etcd/pkg/v3 v3.5.4 h1:V5Dvl7S39ZDwjkKqJG2BfXgxZ3QREqqKifWQgIw5IM0=
-go.etcd.io/etcd/pkg/v3 v3.5.4/go.mod h1:OI+TtO+Aa3nhQSppMbwE4ld3uF1/fqqwbpfndbbrEe0=
+go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0 h1:DvYJotxV9q1Lkn7pknzAbFO/CLtCVidCr2K9qRLJ8pA=
 go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0/go.mod h1:FAwse6Zlm5v4tEWZaTjmNhe17Int4Oxbu7+2r0DiD3w=
-go.etcd.io/etcd/raft/v3 v3.5.4 h1:YGrnAgRfgXloBNuqa+oBI/aRZMcK/1GS6trJePJ/Gqc=
-go.etcd.io/etcd/raft/v3 v3.5.4/go.mod h1:SCuunjYvZFC0fBX0vxMSPjuZmpcSk+XaAcMrD6Do03w=
+go.etcd.io/etcd/server/v3 v3.5.0-alpha.0 h1:fYv7CmmdyuIu27UmKQjS9K/1GtcCa+XnPKqiKBbQkrk=
 go.etcd.io/etcd/server/v3 v3.5.0-alpha.0/go.mod h1:tsKetYpt980ZTpzl/gb+UOJj9RkIyCb1u4wjzMg90BQ=
-go.etcd.io/etcd/server/v3 v3.5.4 h1:CMAZd0g8Bn5NRhynW6pKhc4FRg41/0QYy3d7aNm9874=
-go.etcd.io/etcd/server/v3 v3.5.4/go.mod h1:S5/YTU15KxymM5l3T6b09sNOHPXqGYIZStpuuGbb65c=
 go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -872,27 +860,6 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
 go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
-go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0=
-go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 h1:sO4WKdPAudZGKPcpZT4MJn6JaDmpyLrMPDGGyA1SttE=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
-go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g=
-go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
-go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg=
-go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
-go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8=
-go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
-go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw=
-go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
-go.opentelemetry.io/otel/sdk v0.20.0 h1:JsxtGXd06J8jrnya7fdI/U/MR6yXA5DtbZy+qoHQlr8=
-go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
-go.opentelemetry.io/otel/sdk/export/metric v0.20.0 h1:c5VRjxCXdQlx1HjzwGdQHzZaVI82b5EbBgOu2ljD92g=
-go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
-go.opentelemetry.io/otel/sdk/metric v0.20.0 h1:7ao1wpzHRVKf0OQ7GIxiQJA6X7DLX9o14gmVon7mMK8=
-go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
-go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw=
-go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
-go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -901,7 +868,6 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
@@ -931,9 +897,8 @@ golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
-golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1099,7 +1064,6 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1139,9 +1103,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
 golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
-golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1166,7 +1129,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -1301,7 +1263,6 @@ google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
 google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
 google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
 google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
 google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
 google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
diff --git a/metadata/report/etcd/report_test.go b/metadata/report/etcd/report_test.go
index 663c6918e..09a32e212 100644
--- a/metadata/report/etcd/report_test.go
+++ b/metadata/report/etcd/report_test.go
@@ -19,15 +19,17 @@ package etcd
 
 import (
 	"encoding/json"
-	"net/url"
+	"reflect"
 	"strconv"
 	"testing"
 )
 
 import (
-	"github.com/stretchr/testify/assert"
+	"github.com/agiledragon/gomonkey"
 
-	"go.etcd.io/etcd/server/v3/embed"
+	gxetcd "github.com/dubbogo/gost/database/kv/etcd/v3"
+
+	"go.etcd.io/etcd/client/v3"
 )
 
 import (
@@ -36,114 +38,6 @@ import (
 	"dubbo.apache.org/dubbo-go/v3/metadata/identifier"
 )
 
-const defaultEtcdV3WorkDir = "/tmp/default-dubbo-go-registry.etcd"
-
-func initEtcd(t *testing.T) *embed.Etcd {
-	DefaultListenPeerURLs := "http://localhost:2380"
-	DefaultListenClientURLs := "http://localhost:2379"
-	lpurl, _ := url.Parse(DefaultListenPeerURLs)
-	lcurl, _ := url.Parse(DefaultListenClientURLs)
-	cfg := embed.NewConfig()
-	cfg.LPUrls = []url.URL{*lpurl}
-	cfg.LCUrls = []url.URL{*lcurl}
-	cfg.Dir = defaultEtcdV3WorkDir
-	e, err := embed.StartEtcd(cfg)
-	if err != nil {
-		t.Fatal(err)
-	}
-	return e
-}
-
-func TestEtcdMetadataReportFactory_CreateMetadataReport(t *testing.T) {
-	e := initEtcd(t)
-	url, err := common.NewURL("registry://127.0.0.1:2379", common.WithParamsValue(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER)))
-	if err != nil {
-		t.Fatal(err)
-	}
-	metadataReportFactory := &etcdMetadataReportFactory{}
-	metadataReport := metadataReportFactory.CreateMetadataReport(url)
-	assert.NotNil(t, metadataReport)
-	e.Close()
-}
-
-func TestEtcdMetadataReport_CRUD(t *testing.T) {
-	e := initEtcd(t)
-	url, err := common.NewURL("registry://127.0.0.1:2379", common.WithParamsValue(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER)))
-	if err != nil {
-		t.Fatal(err)
-	}
-	metadataReportFactory := &etcdMetadataReportFactory{}
-	metadataReport := metadataReportFactory.CreateMetadataReport(url)
-	assert.NotNil(t, metadataReport)
-
-	err = metadataReport.StoreConsumerMetadata(newMetadataIdentifier("consumer"), "consumer metadata")
-	assert.Nil(t, err)
-
-	err = metadataReport.StoreProviderMetadata(newMetadataIdentifier("provider"), "provider metadata")
-	assert.Nil(t, err)
-
-	serviceMi := newServiceMetadataIdentifier()
-	serviceUrl, err := common.NewURL("registry://localhost:8848", common.WithParamsValue(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER)))
-	assert.Nil(t, err)
-	err = metadataReport.SaveServiceMetadata(serviceMi, serviceUrl)
-	assert.Nil(t, err)
-
-	subMi := newSubscribeMetadataIdentifier()
-	urlList := make([]string, 0, 1)
-	urlList = append(urlList, serviceUrl.String())
-	urls, _ := json.Marshal(urlList)
-	err = metadataReport.SaveSubscribedData(subMi, string(urls))
-	assert.Nil(t, err)
-
-	serviceUrl, _ = common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
-	metadataInfo := common.NewMetadataInfo(subMi.Application, "", map[string]*common.ServiceInfo{
-		"com.ikurento.user.UserProvider": common.NewServiceInfoWithURL(serviceUrl),
-	})
-	err = metadataReport.RemoveServiceMetadata(serviceMi)
-	assert.Nil(t, err)
-	err = metadataReport.PublishAppMetadata(subMi, metadataInfo)
-	assert.Nil(t, err)
-
-	mdInfo, err := metadataReport.GetAppMetadata(subMi)
-	assert.Nil(t, err)
-	assert.Equal(t, metadataInfo.App, mdInfo.App)
-	assert.Equal(t, metadataInfo.Revision, mdInfo.Revision)
-	assert.Equal(t, 1, len(mdInfo.Services))
-	assert.NotNil(t, metadataInfo.Services["com.ikurento.user.UserProvider"])
-
-	e.Close()
-}
-
-func TestEtcdMetadataReport_ServiceAppMapping(t *testing.T) {
-	e := initEtcd(t)
-	url, err := common.NewURL("registry://127.0.0.1:2379", common.WithParamsValue(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER)))
-	if err != nil {
-		t.Fatal(err)
-	}
-	metadataReportFactory := &etcdMetadataReportFactory{}
-	metadataReport := metadataReportFactory.CreateMetadataReport(url)
-	assert.NotNil(t, metadataReport)
-
-	_, err = metadataReport.GetServiceAppMapping("com.apache.dubbo.sample.basic.IGreeter", "mapping")
-	assert.NotNil(t, err)
-
-	err = metadataReport.RegisterServiceAppMapping("com.apache.dubbo.sample.basic.IGreeter", "mapping", "demo_provider")
-	assert.Nil(t, err)
-	set, err := metadataReport.GetServiceAppMapping("com.apache.dubbo.sample.basic.IGreeter", "mapping")
-	assert.Nil(t, err)
-	assert.Equal(t, 1, set.Size())
-
-	err = metadataReport.RegisterServiceAppMapping("com.apache.dubbo.sample.basic.IGreeter", "mapping", "demo_provider2")
-	assert.Nil(t, err)
-	err = metadataReport.RegisterServiceAppMapping("com.apache.dubbo.sample.basic.IGreeter", "mapping", "demo_provider")
-	assert.Nil(t, err)
-	set, err = metadataReport.GetServiceAppMapping("com.apache.dubbo.sample.basic.IGreeter", "mapping")
-	assert.Nil(t, err)
-	assert.Equal(t, 2, set.Size())
-
-	e.Close()
-}
-
 func newSubscribeMetadataIdentifier() *identifier.SubscriberMetadataIdentifier {
 	return &identifier.SubscriberMetadataIdentifier{
 		Revision: "subscribe",
@@ -177,3 +71,293 @@ func newMetadataIdentifier(side string) *identifier.MetadataIdentifier {
 		},
 	}
 }
+
+type fields struct {
+	client *gxetcd.Client
+	root   string
+}
+type args struct {
+	subscriberMetadataIdentifier *identifier.SubscriberMetadataIdentifier
+	info                         *common.MetadataInfo
+	providerIdentifier           *identifier.MetadataIdentifier
+	serviceDefinitions           string
+	consumerMetadataIdentifier   *identifier.MetadataIdentifier
+	serviceParameterString       string
+	serviceMetadataIdentifier    *identifier.ServiceMetadataIdentifier
+	url                          *common.URL
+	urls                         string
+}
+
+func newEtcdMetadataReport(f fields) *etcdMetadataReport {
+	return &etcdMetadataReport{
+		client: f.client,
+		root:   f.root,
+	}
+}
+
+func Test_etcdMetadataReport_PublishAppMetadata(t *testing.T) {
+	var client *gxetcd.Client
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyMethod(reflect.TypeOf(client), "Put", func(_ *gxetcd.Client, k, v string, opts ...clientv3.OpOption) error {
+		return nil
+	})
+	defer patches.Reset()
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: client,
+				root:   "/dubbo",
+			},
+			args: args{
+				subscriberMetadataIdentifier: newSubscribeMetadataIdentifier(),
+				info:                         &common.MetadataInfo{},
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := newEtcdMetadataReport(tt.fields)
+			if err := e.PublishAppMetadata(tt.args.subscriberMetadataIdentifier, tt.args.info); (err != nil) != tt.wantErr {
+				t.Errorf("PublishAppMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_etcdMetadataReport_StoreProviderMetadata(t *testing.T) {
+	var client *gxetcd.Client
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyMethod(reflect.TypeOf(client), "Put", func(_ *gxetcd.Client, k, v string, opts ...clientv3.OpOption) error {
+		return nil
+	})
+	defer patches.Reset()
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: client,
+				root:   "/dubbo",
+			},
+			args: args{
+				providerIdentifier: newMetadataIdentifier("provuder"),
+				serviceDefinitions: "provider",
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := newEtcdMetadataReport(tt.fields)
+			if err := e.StoreProviderMetadata(tt.args.providerIdentifier, tt.args.serviceDefinitions); (err != nil) != tt.wantErr {
+				t.Errorf("StoreProviderMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_etcdMetadataReport_StoreConsumerMetadata(t *testing.T) {
+	var client *gxetcd.Client
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyMethod(reflect.TypeOf(client), "Put", func(_ *gxetcd.Client, k, v string, opts ...clientv3.OpOption) error {
+		return nil
+	})
+	defer patches.Reset()
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: client,
+				root:   "/dubbo",
+			},
+			args: args{
+				consumerMetadataIdentifier: newMetadataIdentifier("conusmer"),
+				serviceParameterString:     "conusmer",
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := newEtcdMetadataReport(tt.fields)
+			if err := e.StoreConsumerMetadata(tt.args.consumerMetadataIdentifier, tt.args.serviceParameterString); (err != nil) != tt.wantErr {
+				t.Errorf("StoreConsumerMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_etcdMetadataReport_SaveServiceMetadata(t *testing.T) {
+	var client *gxetcd.Client
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyMethod(reflect.TypeOf(client), "Put", func(_ *gxetcd.Client, k, v string, opts ...clientv3.OpOption) error {
+		return nil
+	})
+	defer patches.Reset()
+	serviceURL, _ := common.NewURL("registry://localhost:8848", common.WithParamsValue(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER)))
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: client,
+				root:   "/dubbo",
+			},
+			args: args{
+				serviceMetadataIdentifier: newServiceMetadataIdentifier(),
+				url:                       serviceURL,
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := newEtcdMetadataReport(tt.fields)
+			if err := e.SaveServiceMetadata(tt.args.serviceMetadataIdentifier, tt.args.url); (err != nil) != tt.wantErr {
+				t.Errorf("SaveServiceMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_etcdMetadataReport_SaveSubscribedData(t *testing.T) {
+	var client *gxetcd.Client
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyMethod(reflect.TypeOf(client), "Put", func(_ *gxetcd.Client, k, v string, opts ...clientv3.OpOption) error {
+		return nil
+	})
+	defer patches.Reset()
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: client,
+				root:   "/dubbo",
+			},
+			args: args{
+				subscriberMetadataIdentifier: newSubscribeMetadataIdentifier(),
+				urls:                         "dubbogo",
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := newEtcdMetadataReport(tt.fields)
+			if err := e.SaveSubscribedData(tt.args.subscriberMetadataIdentifier, tt.args.urls); (err != nil) != tt.wantErr {
+				t.Errorf("SaveSubscribedData() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_etcdMetadataReport_RemoveServiceMetadata(t *testing.T) {
+	var client *gxetcd.Client
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyMethod(reflect.TypeOf(client), "Delete", func(_ *gxetcd.Client, k string) error {
+		return nil
+	})
+	defer patches.Reset()
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: client,
+				root:   DEFAULT_ROOT,
+			},
+			args: args{
+				serviceMetadataIdentifier: newServiceMetadataIdentifier(),
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := newEtcdMetadataReport(tt.fields)
+			if err := e.RemoveServiceMetadata(tt.args.serviceMetadataIdentifier); (err != nil) != tt.wantErr {
+				t.Errorf("RemoveServiceMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_etcdMetadataReport_GetAppMetadata(t *testing.T) {
+	info := &common.MetadataInfo{}
+	target, _ := json.Marshal(info)
+	var client *gxetcd.Client
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyMethod(reflect.TypeOf(client), "Get", func(_ *gxetcd.Client, k string) (string, error) {
+		return string(target), nil
+	})
+	defer patches.Reset()
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    *common.MetadataInfo
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: client,
+				root:   DEFAULT_ROOT,
+			},
+			args: args{
+				subscriberMetadataIdentifier: newSubscribeMetadataIdentifier(),
+			},
+			want:    &common.MetadataInfo{},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := newEtcdMetadataReport(tt.fields)
+			got, err := e.GetAppMetadata(tt.args.subscriberMetadataIdentifier)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetAppMetadata() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("GetAppMetadata() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/metadata/report/nacos/report_test.go b/metadata/report/nacos/report_test.go
index c6532a7ef..388bf81a5 100644
--- a/metadata/report/nacos/report_test.go
+++ b/metadata/report/nacos/report_test.go
@@ -18,59 +18,27 @@
 package nacos
 
 import (
-	"net/http"
-	"net/url"
+	"encoding/json"
+	"reflect"
 	"strconv"
 	"testing"
-	"time"
 )
 
 import (
-	"github.com/stretchr/testify/assert"
+	nacosClient "github.com/dubbogo/gost/database/kv/nacos"
+
+	"github.com/golang/mock/gomock"
+
+	"github.com/nacos-group/nacos-sdk-go/model"
+	"github.com/nacos-group/nacos-sdk-go/vo"
 )
 
 import (
 	"dubbo.apache.org/dubbo-go/v3/common"
 	"dubbo.apache.org/dubbo-go/v3/common/constant"
-	"dubbo.apache.org/dubbo-go/v3/common/extension"
 	"dubbo.apache.org/dubbo-go/v3/metadata/identifier"
-	"dubbo.apache.org/dubbo-go/v3/metadata/report"
 )
 
-func TestNacosMetadataReport_CRUD(t *testing.T) {
-	if !checkNacosServerAlive() {
-		return
-	}
-	rpt := newTestReport()
-	assert.NotNil(t, rpt)
-
-	providerMi := newMetadataIdentifier("server")
-	providerMeta := "provider"
-	err := rpt.StoreProviderMetadata(providerMi, providerMeta)
-	assert.Nil(t, err)
-
-	consumerMi := newMetadataIdentifier("client")
-	consumerMeta := "consumer"
-	err = rpt.StoreConsumerMetadata(consumerMi, consumerMeta)
-	assert.Nil(t, err)
-
-	serviceMi := newServiceMetadataIdentifier()
-
-	serviceUrl, _ := common.NewURL("registry://console.nacos.io:80",
-		common.WithParamsValue(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER)),
-		common.WithParamsValue(constant.ClientNameKey, "nacos-client"))
-
-	err = rpt.SaveServiceMetadata(serviceMi, serviceUrl)
-	assert.Nil(t, err)
-
-	exportedUrls, err := rpt.GetExportedURLs(serviceMi)
-	assert.Equal(t, 1, len(exportedUrls))
-	assert.Nil(t, err)
-
-	err = rpt.RemoveServiceMetadata(serviceMi)
-	assert.Nil(t, err)
-}
-
 func newServiceMetadataIdentifier() *identifier.ServiceMetadataIdentifier {
 	return &identifier.ServiceMetadataIdentifier{
 		Protocol: "nacos",
@@ -96,30 +64,435 @@ func newMetadataIdentifier(side string) *identifier.MetadataIdentifier {
 	}
 }
 
-func TestNacosMetadataReportFactory_CreateMetadataReport(t *testing.T) {
-	res := newTestReport()
-	assert.NotNil(t, res)
+// MockIConfigClient is a mock of IConfigClient interface
+type MockIConfigClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockIConfigClientMockRecorder
+}
+
+// MockIConfigClientMockRecorder is the mock recorder for MockIConfigClient
+type MockIConfigClientMockRecorder struct {
+	mock *MockIConfigClient
+}
+
+// NewMockIConfigClient creates a new mock instance
+func NewMockIConfigClient(ctrl *gomock.Controller) *MockIConfigClient {
+	mock := &MockIConfigClient{ctrl: ctrl}
+	mock.recorder = &MockIConfigClientMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *MockIConfigClient) EXPECT() *MockIConfigClientMockRecorder {
+	return m.recorder
+}
+
+// GetConfig mocks base method
+func (m *MockIConfigClient) GetConfig(param vo.ConfigParam) (string, error) {
+	ret := m.ctrl.Call(m, "GetConfig", param)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetConfig indicates an expected call of GetConfig
+func (mr *MockIConfigClientMockRecorder) GetConfig(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfig", reflect.TypeOf((*MockIConfigClient)(nil).GetConfig), param)
+}
+
+// PublishConfig mocks base method
+func (m *MockIConfigClient) PublishConfig(param vo.ConfigParam) (bool, error) {
+	ret := m.ctrl.Call(m, "PublishConfig", param)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
 }
 
-func newTestReport() report.MetadataReport {
-	params := url.Values{}
-	params.Set(constant.NacosNotLoadLocalCache, "true")
+// PublishConfig indicates an expected call of PublishConfig
+func (mr *MockIConfigClientMockRecorder) PublishConfig(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishConfig", reflect.TypeOf((*MockIConfigClient)(nil).PublishConfig), param)
+}
 
-	params.Set(constant.NacosNamespaceID, "nacos")
-	params.Set(constant.TimeoutKey, "5s")
-	params.Set(constant.ClientNameKey, "nacos-client")
-	params.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
+// DeleteConfig mocks base method
+func (m *MockIConfigClient) DeleteConfig(param vo.ConfigParam) (bool, error) {
+	ret := m.ctrl.Call(m, "DeleteConfig", param)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
 
-	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParams(params))
+// DeleteConfig indicates an expected call of DeleteConfig
+func (mr *MockIConfigClientMockRecorder) DeleteConfig(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteConfig", reflect.TypeOf((*MockIConfigClient)(nil).DeleteConfig), param)
+}
 
-	res := extension.GetMetadataReportFactory("nacos").CreateMetadataReport(regurl)
-	return res
+// ListenConfig mocks base method
+func (m *MockIConfigClient) ListenConfig(params vo.ConfigParam) error {
+	ret := m.ctrl.Call(m, "ListenConfig", params)
+	ret0, _ := ret[0].(error)
+	return ret0
 }
 
-func checkNacosServerAlive() bool {
-	c := http.Client{Timeout: time.Second}
-	if _, err := c.Get("http://console.nacos.io/nacos/"); err != nil {
-		return false
+// ListenConfig indicates an expected call of ListenConfig
+func (mr *MockIConfigClientMockRecorder) ListenConfig(params interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListenConfig", reflect.TypeOf((*MockIConfigClient)(nil).ListenConfig), params)
+}
+
+// CancelListenConfig mocks base method
+func (m *MockIConfigClient) CancelListenConfig(params vo.ConfigParam) error {
+	ret := m.ctrl.Call(m, "CancelListenConfig", params)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// CancelListenConfig indicates an expected call of CancelListenConfig
+func (mr *MockIConfigClientMockRecorder) CancelListenConfig(params interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelListenConfig", reflect.TypeOf((*MockIConfigClient)(nil).CancelListenConfig), params)
+}
+
+// SearchConfig mocks base method
+func (m *MockIConfigClient) SearchConfig(param vo.SearchConfigParam) (*model.ConfigPage, error) {
+	ret := m.ctrl.Call(m, "SearchConfig", param)
+	ret0, _ := ret[0].(*model.ConfigPage)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// SearchConfig indicates an expected call of SearchConfig
+func (mr *MockIConfigClientMockRecorder) SearchConfig(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchConfig", reflect.TypeOf((*MockIConfigClient)(nil).SearchConfig), param)
+}
+
+// PublishAggr mocks base method
+func (m *MockIConfigClient) PublishAggr(param vo.ConfigParam) (bool, error) {
+	ret := m.ctrl.Call(m, "PublishAggr", param)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// PublishAggr indicates an expected call of PublishAggr
+func (mr *MockIConfigClientMockRecorder) PublishAggr(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishAggr", reflect.TypeOf((*MockIConfigClient)(nil).PublishAggr), param)
+}
+
+type fields struct {
+	client *nacosClient.NacosConfigClient
+}
+type args struct {
+	subscriberMetadataIdentifier *identifier.SubscriberMetadataIdentifier
+	info                         *common.MetadataInfo
+	providerIdentifier           *identifier.MetadataIdentifier
+	serviceDefinitions           string
+	consumerMetadataIdentifier   *identifier.MetadataIdentifier
+	serviceParameterString       string
+	url                          *common.URL
+	serviceMetadataIdentifier    *identifier.ServiceMetadataIdentifier
+	urls                         string
+	key                          string
+	group                        string
+	value                        string
+}
+
+func newNacosMetadataReport(f fields) *nacosMetadataReport {
+	return &nacosMetadataReport{
+		client: f.client,
+	}
+}
+
+func Test_nacosMetadataReport_GetAppMetadata(t *testing.T) {
+	mi := common.MetadataInfo{
+		App: "GetAppMetadata",
+	}
+	data, _ := json.Marshal(mi)
+
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().GetConfig(gomock.Any()).Return(string(data), nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    *common.MetadataInfo
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				subscriberMetadataIdentifier: &identifier.SubscriberMetadataIdentifier{},
+			},
+			want:    &mi,
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newNacosMetadataReport(tt.fields)
+			got, err := n.GetAppMetadata(tt.args.subscriberMetadataIdentifier)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetAppMetadata() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("GetAppMetadata() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_nacosMetadataReport_PublishAppMetadata(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().PublishConfig(gomock.Any()).Return(true, nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				subscriberMetadataIdentifier: &identifier.SubscriberMetadataIdentifier{},
+				info: &common.MetadataInfo{
+					App: "PublishAppMetadata",
+				},
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newNacosMetadataReport(tt.fields)
+			if err := n.PublishAppMetadata(tt.args.subscriberMetadataIdentifier, tt.args.info); (err != nil) != tt.wantErr {
+				t.Errorf("PublishAppMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_nacosMetadataReport_StoreProviderMetadata(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().PublishConfig(gomock.Any()).Return(true, nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				providerIdentifier: newMetadataIdentifier("provider"),
+				serviceDefinitions: "provider",
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newNacosMetadataReport(tt.fields)
+			if err := n.StoreProviderMetadata(tt.args.providerIdentifier, tt.args.serviceDefinitions); (err != nil) != tt.wantErr {
+				t.Errorf("StoreProviderMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_nacosMetadataReport_StoreConsumerMetadata(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().PublishConfig(gomock.Any()).Return(true, nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				consumerMetadataIdentifier: newMetadataIdentifier("conusmer"),
+				serviceParameterString:     "conusmer",
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newNacosMetadataReport(tt.fields)
+			if err := n.StoreConsumerMetadata(tt.args.consumerMetadataIdentifier, tt.args.serviceParameterString); (err != nil) != tt.wantErr {
+				t.Errorf("StoreConsumerMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_nacosMetadataReport_SaveServiceMetadata(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().PublishConfig(gomock.Any()).Return(true, nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	serviceURL, _ := common.NewURL("registry://test.nacos.io:80",
+		common.WithParamsValue(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER)),
+		common.WithParamsValue(constant.ClientNameKey, "nacos-client"))
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				serviceMetadataIdentifier: newServiceMetadataIdentifier(),
+				url:                       serviceURL,
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newNacosMetadataReport(tt.fields)
+			if err := n.SaveServiceMetadata(tt.args.serviceMetadataIdentifier, tt.args.url); (err != nil) != tt.wantErr {
+				t.Errorf("SaveServiceMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_nacosMetadataReport_RemoveServiceMetadata(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().DeleteConfig(gomock.Any()).Return(true, nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				serviceMetadataIdentifier: newServiceMetadataIdentifier(),
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newNacosMetadataReport(tt.fields)
+			if err := n.RemoveServiceMetadata(tt.args.serviceMetadataIdentifier); (err != nil) != tt.wantErr {
+				t.Errorf("RemoveServiceMetadata() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_nacosMetadataReport_SaveSubscribedData(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().PublishConfig(gomock.Any()).Return(true, nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				subscriberMetadataIdentifier: &identifier.SubscriberMetadataIdentifier{},
+				urls:                         "urls",
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newNacosMetadataReport(tt.fields)
+			if err := n.SaveSubscribedData(tt.args.subscriberMetadataIdentifier, tt.args.urls); (err != nil) != tt.wantErr {
+				t.Errorf("SaveSubscribedData() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_nacosMetadataReport_RegisterServiceAppMapping(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	mnc := NewMockIConfigClient(ctrl)
+	mnc.EXPECT().GetConfig(gomock.Any()).Return("oldValue", nil)
+	nc := &nacosClient.NacosConfigClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: nc,
+			},
+			args: args{
+				key:   "test",
+				group: "test",
+				value: "oldValue",
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := newNacosMetadataReport(tt.fields)
+			if err := n.RegisterServiceAppMapping(tt.args.key, tt.args.group, tt.args.value); (err != nil) != tt.wantErr {
+				t.Errorf("RegisterServiceAppMapping() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
 	}
-	return true
 }
diff --git a/registry/etcdv3/listener_test.go b/registry/etcdv3/listener_test.go
index 97f95e0f4..da3154c24 100644
--- a/registry/etcdv3/listener_test.go
+++ b/registry/etcdv3/listener_test.go
@@ -18,17 +18,7 @@
 package etcdv3
 
 import (
-	"os"
 	"testing"
-	"time"
-)
-
-import (
-	gxtime "github.com/dubbogo/gost/time"
-
-	"github.com/stretchr/testify/suite"
-
-	"go.etcd.io/etcd/server/v3/embed"
 )
 
 import (
@@ -37,60 +27,48 @@ import (
 	"dubbo.apache.org/dubbo-go/v3/remoting"
 )
 
-type RegistryTestSuite struct {
-	suite.Suite
-	etcd *embed.Etcd
-}
-
-const defaultEtcdV3WorkDir = "/tmp/default-dubbo-go-registry.etcd"
-
-// start etcd server
-func (suite *RegistryTestSuite) SetupSuite() {
-	t := suite.T()
-
-	cfg := embed.NewConfig()
-	// avoid conflict with default etcd work-dir
-	cfg.Dir = defaultEtcdV3WorkDir
-	e, err := embed.StartEtcd(cfg)
-	if err != nil {
-		t.Fatal(err)
-	}
+type MockDataListener struct{}
 
-	select {
-	case <-e.Server.ReadyNotify():
-		t.Log("Server is ready!")
-	case <-gxtime.After(60 * time.Second):
-		e.Server.Stop() // trigger a shutdown
-		t.Logf("Server took too long to start!")
-	}
+func (*MockDataListener) Process(configType *config_center.ConfigChangeEvent) {}
 
-	suite.etcd = e
+type dataListenerFields struct {
+	interestedURL []*common.URL
+	listener      config_center.ConfigurationListener
 }
 
-// stop etcd server
-func (suite *RegistryTestSuite) TearDownSuite() {
-	suite.etcd.Close()
-	// clean the etcd workdir
-	if err := os.RemoveAll(defaultEtcdV3WorkDir); err != nil {
-		suite.FailNow(err.Error())
+func newDataListener(listenerFields dataListenerFields) *dataListener {
+	return &dataListener{
+		interestedURL: listenerFields.interestedURL,
+		listener:      listenerFields.listener,
 	}
 }
-
-func (suite *RegistryTestSuite) TestDataChange() {
-	t := suite.T()
-
-	listener := NewRegistryDataListener(&MockDataListener{})
-	url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bs [...]
-	listener.AddInterestedURL(url)
-	if !listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retrie [...]
-		t.Fatal("data change not ok")
+func Test_dataListener_DataChange(t *testing.T) {
+	tests := []struct {
+		name   string
+		fields dataListenerFields
+		args   args
+		want   bool
+	}{
+		{
+			name: "test",
+			fields: dataListenerFields{
+				interestedURL: nil,
+				listener:      &MockDataListener{},
+			},
+			args: args{
+				eventType: remoting.Event{
+					Path: "com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26modul [...]
+				},
+			},
+			want: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			l := newDataListener(tt.fields)
+			if got := l.DataChange(tt.args.eventType); got != tt.want {
+				t.Errorf("DataChange() = %v, want %v", got, tt.want)
+			}
+		})
 	}
 }
-
-func TestRegistrySuite(t *testing.T) {
-	suite.Run(t, &RegistryTestSuite{})
-}
-
-type MockDataListener struct{}
-
-func (*MockDataListener) Process(configType *config_center.ConfigChangeEvent) {}
diff --git a/registry/etcdv3/registry_test.go b/registry/etcdv3/registry_test.go
index 7ff64057f..56aa2e7b0 100644
--- a/registry/etcdv3/registry_test.go
+++ b/registry/etcdv3/registry_test.go
@@ -15,113 +15,105 @@
  * limitations under the License.
  */
 
+// nolint
 package etcdv3
 
 import (
-	"strconv"
+	"reflect"
+	"sync"
 	"testing"
-	"time"
 )
 
 import (
-	"github.com/stretchr/testify/assert"
+	"github.com/agiledragon/gomonkey"
+
+	gxetcd "github.com/dubbogo/gost/database/kv/etcd/v3"
 )
 
 import (
-	"dubbo.apache.org/dubbo-go/v3/common"
-	"dubbo.apache.org/dubbo-go/v3/common/constant"
+	"dubbo.apache.org/dubbo-go/v3/registry"
+	"dubbo.apache.org/dubbo-go/v3/remoting"
+	"dubbo.apache.org/dubbo-go/v3/remoting/etcdv3"
 )
 
-func initRegistry(t *testing.T) *etcdV3Registry {
-	regurl, err := common.NewURL("registry://127.0.0.1:2379", common.WithParamsValue(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER)))
-	if err != nil {
-		t.Fatal(err)
-	}
+type fields struct {
+	BaseRegistry   registry.BaseRegistry
+	cltLock        sync.Mutex
+	client         *gxetcd.Client
+	listenerLock   sync.RWMutex
+	listener       *etcdv3.EventListener
+	dataListener   *dataListener
+	configListener *configurationListener
+}
+type args struct {
+	root      string
+	node      string
+	eventType remoting.Event
+}
 
-	reg, err := newETCDV3Registry(regurl)
-	if err != nil {
-		t.Fatal(err)
+func newEtcdV3Registry(f fields) *etcdV3Registry {
+	return &etcdV3Registry{
+		client:         f.client,
+		listener:       f.listener,
+		dataListener:   f.dataListener,
+		configListener: f.configListener,
 	}
-
-	out := reg.(*etcdV3Registry)
-	err = out.client.CleanKV()
-	assert.NoError(t, err)
-	return out
 }
 
-//
-//func (suite *RegistryTestSuite) TestRegister() {
-//	t := suite.T()
-//
-//	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.ClusterKey, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
-//
-//	reg := initRegistry(t)
-//	err := reg.Register(url)
-//	assert.NoError(t, err)
-//	children, _, err := reg.client.GetChildrenKVList("/dubbo/com.ikurento.user.UserProvider/providers")
-//	if err != nil {
-//		t.Fatal(err)
-//	}
-//	assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26cluster%3Dmock", children)
-//	assert.NoError(t, err)
-//}
-//
-//func (suite *RegistryTestSuite) TestSubscribe() {
-//	t := suite.T()
-//	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER)))
-//	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.ClusterKey, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
-//
-//	reg := initRegistry(t)
-//	// provider register
-//	err := reg.Register(url)
-//	if err != nil {
-//		t.Fatal(err)
-//	}
-//
-//	// consumer register
-//	regurl.SetParam(constant.RegistryRoleKey, strconv.Itoa(common.Consumer))
-//	reg2 := initRegistry(t)
-//
-//	err = reg2.Register(url)
-//	assert.NoError(t, err)
-//	listener, err := reg2.DoSubscribe(url)
-//	if err != nil {
-//		t.Fatal(err)
-//	}
-//
-//	serviceEvent, err := listener.Next()
-//	if err != nil {
-//		t.Fatal(err)
-//	}
-//	assert.Regexp(t, ".*ServiceEvent{Action{add}.*", serviceEvent.String())
-//}
-
-func (suite *RegistryTestSuite) TestConsumerDestroy() {
-	t := suite.T()
-	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.ClusterKey, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+func Test_etcdV3Registry_DoRegister(t *testing.T) {
+	var client *gxetcd.Client
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyMethod(reflect.TypeOf(client), "RegisterTemp", func(_ *gxetcd.Client, k, v string) error {
+		return nil
+	})
+	defer patches.Reset()
 
-	reg := initRegistry(t)
-	_, err := reg.DoSubscribe(url)
-	if err != nil {
-		t.Fatal(err)
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				client: client,
+			},
+			args: args{
+				root: "/dubbo",
+				node: "/go",
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			r := newEtcdV3Registry(tt.fields)
+			if err := r.DoRegister(tt.args.root, tt.args.node); (err != nil) != tt.wantErr {
+				t.Errorf("DoRegister() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
 	}
-
-	// listener.Close()
-	time.Sleep(1e9)
-	reg.Destroy()
-
-	assert.Equal(t, false, reg.IsAvailable())
 }
 
-func (suite *RegistryTestSuite) TestProviderDestroy() {
-	t := suite.T()
-	reg := initRegistry(t)
-	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.ClusterKey, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
-	err := reg.Register(url)
-	assert.NoError(t, err)
-
-	// listener.Close()
-	time.Sleep(1e9)
-	reg.Destroy()
-	assert.Equal(t, false, reg.IsAvailable())
+func Test_etcdV3Registry_DoUnregister(t *testing.T) {
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name:    "test",
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			r := newEtcdV3Registry(tt.fields)
+			if err := r.DoUnregister(tt.args.root, tt.args.node); (err != nil) != tt.wantErr {
+				t.Errorf("DoUnregister() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
 }
diff --git a/registry/nacos/registry_test.go b/registry/nacos/registry_test.go
index 1e467b78c..1012b8487 100644
--- a/registry/nacos/registry_test.go
+++ b/registry/nacos/registry_test.go
@@ -18,36 +18,203 @@
 package nacos
 
 import (
-	"encoding/json"
-	"net/http"
 	"net/url"
+	"reflect"
 	"strconv"
 	"testing"
-	"time"
 )
 
 import (
-	"github.com/nacos-group/nacos-sdk-go/vo"
+	nacosClient "github.com/dubbogo/gost/database/kv/nacos"
+
+	"github.com/golang/mock/gomock"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/nacos-group/nacos-sdk-go/model"
+	"github.com/nacos-group/nacos-sdk-go/vo"
 )
 
 import (
 	"dubbo.apache.org/dubbo-go/v3/common"
 	"dubbo.apache.org/dubbo-go/v3/common/constant"
+	"dubbo.apache.org/dubbo-go/v3/registry"
 )
 
-func TestNacosRegistry_Register(t *testing.T) {
-	//t.Skip()
-	if !checkNacosServerAlive() {
-		return
+// MockINamingClient is a mock of INamingClient interface
+type MockINamingClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockINamingClientMockRecorder
+}
+
+// MockINamingClientMockRecorder is the mock recorder for MockINamingClient
+type MockINamingClientMockRecorder struct {
+	mock *MockINamingClient
+}
+
+// NewMockINamingClient creates a new mock instance
+func NewMockINamingClient(ctrl *gomock.Controller) *MockINamingClient {
+	mock := &MockINamingClient{ctrl: ctrl}
+	mock.recorder = &MockINamingClientMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *MockINamingClient) EXPECT() *MockINamingClientMockRecorder {
+	return m.recorder
+}
+
+// RegisterInstance mocks base method
+func (m *MockINamingClient) RegisterInstance(param vo.RegisterInstanceParam) (bool, error) {
+	ret := m.ctrl.Call(m, "RegisterInstance", param)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// RegisterInstance indicates an expected call of RegisterInstance
+func (mr *MockINamingClientMockRecorder) RegisterInstance(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInstance", reflect.TypeOf((*MockINamingClient)(nil).RegisterInstance), param)
+}
+
+// DeregisterInstance mocks base method
+func (m *MockINamingClient) DeregisterInstance(param vo.DeregisterInstanceParam) (bool, error) {
+	ret := m.ctrl.Call(m, "DeregisterInstance", param)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DeregisterInstance indicates an expected call of DeregisterInstance
+func (mr *MockINamingClientMockRecorder) DeregisterInstance(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeregisterInstance", reflect.TypeOf((*MockINamingClient)(nil).DeregisterInstance), param)
+}
+
+// UpdateInstance mocks base method
+func (m *MockINamingClient) UpdateInstance(param vo.UpdateInstanceParam) (bool, error) {
+	ret := m.ctrl.Call(m, "UpdateInstance", param)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpdateInstance indicates an expected call of UpdateInstance
+func (mr *MockINamingClientMockRecorder) UpdateInstance(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateInstance", reflect.TypeOf((*MockINamingClient)(nil).UpdateInstance), param)
+}
+
+// GetService mocks base method
+func (m *MockINamingClient) GetService(param vo.GetServiceParam) (model.Service, error) {
+	ret := m.ctrl.Call(m, "GetService", param)
+	ret0, _ := ret[0].(model.Service)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetService indicates an expected call of GetService
+func (mr *MockINamingClientMockRecorder) GetService(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*MockINamingClient)(nil).GetService), param)
+}
+
+// SelectAllInstances mocks base method
+func (m *MockINamingClient) SelectAllInstances(param vo.SelectAllInstancesParam) ([]model.Instance, error) {
+	ret := m.ctrl.Call(m, "SelectAllInstances", param)
+	ret0, _ := ret[0].([]model.Instance)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// SelectAllInstances indicates an expected call of SelectAllInstances
+func (mr *MockINamingClientMockRecorder) SelectAllInstances(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectAllInstances", reflect.TypeOf((*MockINamingClient)(nil).SelectAllInstances), param)
+}
+
+// SelectInstances mocks base method
+func (m *MockINamingClient) SelectInstances(param vo.SelectInstancesParam) ([]model.Instance, error) {
+	ret := m.ctrl.Call(m, "SelectInstances", param)
+	ret0, _ := ret[0].([]model.Instance)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// SelectInstances indicates an expected call of SelectInstances
+func (mr *MockINamingClientMockRecorder) SelectInstances(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectInstances", reflect.TypeOf((*MockINamingClient)(nil).SelectInstances), param)
+}
+
+// SelectOneHealthyInstance mocks base method
+func (m *MockINamingClient) SelectOneHealthyInstance(param vo.SelectOneHealthInstanceParam) (*model.Instance, error) {
+	ret := m.ctrl.Call(m, "SelectOneHealthyInstance", param)
+	ret0, _ := ret[0].(*model.Instance)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// SelectOneHealthyInstance indicates an expected call of SelectOneHealthyInstance
+func (mr *MockINamingClientMockRecorder) SelectOneHealthyInstance(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectOneHealthyInstance", reflect.TypeOf((*MockINamingClient)(nil).SelectOneHealthyInstance), param)
+}
+
+// Subscribe mocks base method
+func (m *MockINamingClient) Subscribe(param *vo.SubscribeParam) error {
+	ret := m.ctrl.Call(m, "Subscribe", param)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Subscribe indicates an expected call of Subscribe
+func (mr *MockINamingClientMockRecorder) Subscribe(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockINamingClient)(nil).Subscribe), param)
+}
+
+// Unsubscribe mocks base method
+func (m *MockINamingClient) Unsubscribe(param *vo.SubscribeParam) error {
+	ret := m.ctrl.Call(m, "Unsubscribe", param)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Unsubscribe indicates an expected call of Unsubscribe
+func (mr *MockINamingClientMockRecorder) Unsubscribe(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unsubscribe", reflect.TypeOf((*MockINamingClient)(nil).Unsubscribe), param)
+}
+
+// GetAllServicesInfo mocks base method
+func (m *MockINamingClient) GetAllServicesInfo(param vo.GetAllServiceInfoParam) (model.ServiceList, error) {
+	ret := m.ctrl.Call(m, "GetAllServicesInfo", param)
+	ret0, _ := ret[0].(model.ServiceList)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetAllServicesInfo indicates an expected call of GetAllServicesInfo
+func (mr *MockINamingClientMockRecorder) GetAllServicesInfo(param interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllServicesInfo", reflect.TypeOf((*MockINamingClient)(nil).GetAllServicesInfo), param)
+}
+
+type fields struct {
+	URL          *common.URL
+	namingClient *nacosClient.NacosNamingClient
+	registryUrls []*common.URL
+}
+type args struct {
+	url            *common.URL
+	notifyListener registry.NotifyListener
+}
+
+func newNacosRegistryForTest(f fields) *nacosRegistry {
+	return &nacosRegistry{
+		URL:          f.URL,
+		namingClient: f.namingClient,
+		registryUrls: f.registryUrls,
 	}
+}
+
+func Test_nacosRegistry_Register(t *testing.T) {
 	params := url.Values{}
 	params.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
 	params.Set(constant.NacosNotLoadLocalCache, "true")
 	params.Set(constant.ClientNameKey, "nacos-client")
 
-	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParams(params))
+	regURL, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(params))
 
 	urlMap := url.Values{}
 	urlMap.Set(constant.GroupKey, "guangzhou-idc")
@@ -56,185 +223,142 @@ func TestNacosRegistry_Register(t *testing.T) {
 	urlMap.Set(constant.VersionKey, "1.0.0")
 	urlMap.Set(constant.ClusterKey, "mock")
 	urlMap.Set(constant.ClientNameKey, "nacos-client")
-	testUrl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	testURL, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	reg, err := newNacosRegistry(regurl)
-	assert.Nil(t, err)
-	if err != nil {
-		t.Errorf("new nacos registry error:%s \n", err.Error())
-		return
+	ctrl := gomock.NewController(t)
+	mnc := NewMockINamingClient(ctrl)
+	mnc.EXPECT().RegisterInstance(gomock.Any()).Return(true, nil)
+	nc := &nacosClient.NacosNamingClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				URL:          regURL,
+				namingClient: nc,
+				registryUrls: nil,
+			},
+			args: args{
+				url: testURL,
+			},
+			wantErr: false,
+		},
 	}
-	err = reg.Register(testUrl)
-	assert.Nil(t, err)
-	if err != nil {
-		t.Errorf("register error:%s \n", err.Error())
-		return
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			nr := newNacosRegistryForTest(tt.fields)
+			if err := nr.Register(tt.args.url); (err != nil) != tt.wantErr {
+				t.Errorf("Register() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
 	}
-	time.Sleep(5 * time.Second)
-	nacosReg := reg.(*nacosRegistry)
-	service, _ := nacosReg.namingClient.Client().GetService(vo.GetServiceParam{ServiceName: "providers:com.ikurento.user.UserProvider:1.0.0:guangzhou-idc"})
-	data, _ := json.Marshal(service)
-	t.Logf(string(data))
-	assert.Equal(t, 1, len(service.Hosts))
 }
 
-func TestNacosRegistry_Subscribe(t *testing.T) {
-	if !checkNacosServerAlive() {
-		return
-	}
-	regurlMap := url.Values{}
-	regurlMap.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
-	regurlMap.Set(constant.NacosNotLoadLocalCache, "true")
-	regurlMap.Set(constant.ClientNameKey, "nacos-client")
-	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParams(regurlMap))
+func Test_nacosRegistry_UnRegister(t *testing.T) {
+	params := url.Values{}
+	params.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
+	params.Set(constant.NacosNotLoadLocalCache, "true")
+	params.Set(constant.ClientNameKey, "nacos-client")
+
+	regURL, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(params))
 
 	urlMap := url.Values{}
 	urlMap.Set(constant.GroupKey, "guangzhou-idc")
 	urlMap.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
-	urlMap.Set(constant.InterfaceKey, "com.dubbo.user.UserProvider")
+	urlMap.Set(constant.InterfaceKey, "com.ikurento.user.UserProvider")
 	urlMap.Set(constant.VersionKey, "1.0.0")
 	urlMap.Set(constant.ClusterKey, "mock")
-	urlMap.Set(constant.NacosPathKey, "")
 	urlMap.Set(constant.ClientNameKey, "nacos-client")
-	testUrl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.dubbo.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
-
-	reg, _ := newNacosRegistry(regurl)
-	err := reg.Register(testUrl)
-	assert.Nil(t, err)
-	if err != nil {
-		t.Errorf("new nacos registry error:%s \n", err.Error())
-		return
-	}
+	testURL, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	regurl.SetParam(constant.RegistryRoleKey, strconv.Itoa(common.CONSUMER))
-	reg2, _ := newNacosRegistry(regurl)
-	listener, err := reg2.(*nacosRegistry).subscribe(testUrl)
-	assert.Nil(t, err)
-	if err != nil {
-		t.Errorf("subscribe error:%s \n", err.Error())
-		return
+	ctrl := gomock.NewController(t)
+	mnc := NewMockINamingClient(ctrl)
+	mnc.EXPECT().DeregisterInstance(gomock.Any()).Return(true, nil)
+	nc := &nacosClient.NacosNamingClient{}
+	nc.SetClient(mnc)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				URL:          regURL,
+				namingClient: nc,
+				registryUrls: nil,
+			},
+			args: args{
+				url: testURL,
+			},
+			wantErr: false,
+		},
 	}
-	serviceEvent, _ := listener.Next()
-	assert.NoError(t, err)
-	if err != nil {
-		t.Errorf("listener error:%s \n", err.Error())
-		return
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			nr := newNacosRegistryForTest(tt.fields)
+			if err := nr.UnRegister(tt.args.url); (err != nil) != tt.wantErr {
+				t.Errorf("UnRegister() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
 	}
-	t.Logf("serviceEvent:%+v \n", serviceEvent)
-	assert.Regexp(t, ".*ServiceEvent{Action{add}.*", serviceEvent.String())
 }
 
-func TestNacosRegistry_Subscribe_del(t *testing.T) {
-	if !checkNacosServerAlive() {
-		return
-	}
-	regurlMap := url.Values{}
-	regurlMap.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
-	regurlMap.Set(constant.NacosNotLoadLocalCache, "true")
-	regurlMap.Set(constant.ClientNameKey, "nacos-client")
-	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParams(regurlMap))
+func Test_nacosRegistry_Subscribe(t *testing.T) {
+	params := url.Values{}
+	params.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
+	params.Set(constant.NacosNotLoadLocalCache, "true")
+	params.Set(constant.ClientNameKey, "nacos-client")
+
+	regURL, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(params))
 
 	urlMap := url.Values{}
 	urlMap.Set(constant.GroupKey, "guangzhou-idc")
 	urlMap.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
 	urlMap.Set(constant.InterfaceKey, "com.ikurento.user.UserProvider")
-	urlMap.Set(constant.VersionKey, "2.0.0")
+	urlMap.Set(constant.VersionKey, "1.0.0")
 	urlMap.Set(constant.ClusterKey, "mock")
-	urlMap.Set(constant.NacosPathKey, "")
 	urlMap.Set(constant.ClientNameKey, "nacos-client")
-	url1, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
-	url2, _ := common.NewURL("dubbo://127.0.0.2:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
-
-	reg, _ := newNacosRegistry(regurl)
-	err := reg.Register(url1)
-	assert.Nil(t, err)
-	if err != nil {
-		t.Errorf("register1 error:%s \n", err.Error())
-		return
-	}
-	err = reg.Register(url2)
-	assert.Nil(t, err)
-	if err != nil {
-		t.Errorf("register2 error:%s \n", err.Error())
-		return
-	}
-
-	regurl.SetParam(constant.RegistryRoleKey, strconv.Itoa(common.CONSUMER))
-	reg2, _ := newNacosRegistry(regurl)
-	listener, err := reg2.(*nacosRegistry).subscribe(url1)
-	assert.Nil(t, err)
-	if err != nil {
-		t.Errorf("subscribe error:%s \n", err.Error())
-		return
-	}
-
-	serviceEvent1, _ := listener.Next()
-	assert.NoError(t, err)
-	if err != nil {
-		t.Errorf("listener1 error:%s \n", err.Error())
-		return
-	}
-	t.Logf("serviceEvent1:%+v \n", serviceEvent1)
-	assert.Regexp(t, ".*ServiceEvent{Action{add}.*", serviceEvent1.String())
-
-	serviceEvent2, _ := listener.Next()
-	assert.NoError(t, err)
-	if err != nil {
-		t.Errorf("listener2 error:%s \n", err.Error())
-		return
-	}
-	t.Logf("serviceEvent2:%+v \n", serviceEvent2)
-	assert.Regexp(t, ".*ServiceEvent{Action{add}.*", serviceEvent2.String())
-
-	nacosReg := reg.(*nacosRegistry)
-	// deregister instance to mock instance offline
-	_, err = nacosReg.namingClient.Client().DeregisterInstance(vo.DeregisterInstanceParam{
-		Ip: "127.0.0.2", Port: 20000,
-		ServiceName: "providers:com.ikurento.user.UserProvider:2.0.0:guangzhou-idc",
-	})
-	assert.NoError(t, err)
-
-	serviceEvent3, _ := listener.Next()
-	assert.NoError(t, err)
-	if err != nil {
-		return
-	}
-	t.Logf("serviceEvent3:%+v \n", serviceEvent3)
-	assert.Regexp(t, ".*ServiceEvent{Action{delete}.*", serviceEvent3.String())
-}
+	testURL, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-func TestNacosListener_Close(t *testing.T) {
-	regurlMap := url.Values{}
-	regurlMap.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
-	regurlMap.Set(constant.NacosNotLoadLocalCache, "true")
-	regurlMap.Set(constant.ClientNameKey, "nacos-client")
-	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParams(regurlMap))
+	ctrl := gomock.NewController(t)
+	mnc := NewMockINamingClient(ctrl)
+	nc := &nacosClient.NacosNamingClient{}
+	nc.SetClient(mnc)
 
-	urlMap := url.Values{}
-	urlMap.Set(constant.RegistryGroupKey, "guangzhou-idc")
-	urlMap.Set(constant.RegistryRoleKey, strconv.Itoa(common.PROVIDER))
-	urlMap.Set(constant.InterfaceKey, "com.ikurento.user.UserProvider2")
-	urlMap.Set(constant.VersionKey, "1.0.0")
-	urlMap.Set(constant.ClusterKey, "mock")
-	urlMap.Set(constant.NacosPathKey, "")
-	urlMap.Set(constant.ClientNameKey, "nacos-client")
-	url1, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider2", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
-	reg, _ := newNacosRegistry(regurl)
-	listener, err := reg.(*nacosRegistry).subscribe(url1)
-	assert.Nil(t, err)
-	if err != nil {
-		t.Errorf("subscribe error:%s \n", err.Error())
-		return
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "test",
+			fields: fields{
+				URL:          regURL,
+				namingClient: nc,
+				registryUrls: nil,
+			},
+			args: args{
+				url: testURL,
+			},
+			wantErr: false,
+		},
 	}
-	listener.Close()
-	_, err = listener.Next()
-	assert.NotNil(t, err)
-}
-
-func checkNacosServerAlive() bool {
-	c := http.Client{Timeout: time.Second}
-	if _, err := c.Get("http://console.nacos.io/nacos/"); err != nil {
-		return false
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			nr := newNacosRegistryForTest(tt.fields)
+			if err := nr.Subscribe(tt.args.url, tt.args.notifyListener); (err != nil) != tt.wantErr {
+				t.Errorf("Subscribe() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
 	}
-	return true
 }
diff --git a/remoting/etcdv3/listener_test.go b/remoting/etcdv3/listener_test.go
index b6b7397c4..f8b4263ea 100644
--- a/remoting/etcdv3/listener_test.go
+++ b/remoting/etcdv3/listener_test.go
@@ -18,129 +18,37 @@
 package etcdv3
 
 import (
-	"net/url"
-	"os"
+	"reflect"
 	"testing"
-	"time"
 )
 
 import (
 	gxetcd "github.com/dubbogo/gost/database/kv/etcd/v3"
-
-	"github.com/stretchr/testify/assert"
-
-	"go.etcd.io/etcd/server/v3/embed"
-)
-
-import (
-	"dubbo.apache.org/dubbo-go/v3/remoting"
 )
 
-const defaultEtcdV3WorkDir = "/tmp/default-dubbo-go-remote.etcd"
-
-var changedData = `
-	dubbo.consumer.request_timeout=3s
-	dubbo.consumer.connect_timeout=5s
-	dubbo.application.organization=ikurento.com
-	dubbo.application.name=BDTService
-	dubbo.application.module=dubbogo user-info server
-	dubbo.application.version=0.0.1
-	dubbo.application.owner=ZX
-	dubbo.application.environment=dev
-	dubbo.registries.hangzhouzk.protocol=zookeeper
-	dubbo.registries.hangzhouzk.timeout=3s
-	dubbo.registries.hangzhouzk.address=127.0.0.1:2181
-	dubbo.registries.shanghaizk.protocol=zookeeper
-	dubbo.registries.shanghaizk.timeout=3s
-	dubbo.registries.shanghaizk.address=127.0.0.1:2182
-	dubbo.service.com.ikurento.user.UserProvider.protocol=dubbo
-	dubbo.service.com.ikurento.user.UserProvider.interface=com.ikurento.user.UserProvider
-	dubbo.service.com.ikurento.user.UserProvider.loadbalance=random
-	dubbo.service.com.ikurento.user.UserProvider.warmup=100
-	dubbo.service.com.ikurento.user.UserProvider.cluster=failover
-`
-
-var etcd *embed.Etcd
-
-func SetUpEtcdServer(t *testing.T) {
-	var err error
-	DefaultListenPeerURLs := "http://localhost:2382"
-	DefaultListenClientURLs := "http://localhost:2381"
-	lpurl, _ := url.Parse(DefaultListenPeerURLs)
-	lcurl, _ := url.Parse(DefaultListenClientURLs)
-	cfg := embed.NewConfig()
-	cfg.LPUrls = []url.URL{*lpurl}
-	cfg.LCUrls = []url.URL{*lcurl}
-	cfg.Dir = defaultEtcdV3WorkDir
-	etcd, err = embed.StartEtcd(cfg)
-	if err != nil {
-		t.Fatal(err)
-	}
-	select {
-	case <-etcd.Server.ReadyNotify():
-		t.Log("Server is ready!")
-	case <-time.After(60 * time.Second):
-		etcd.Server.Stop() // trigger a shutdown
-		t.Logf("Server took too long to start!")
-	}
-}
-
-func ClearEtcdServer(t *testing.T) {
-	etcd.Close()
-	if err := os.RemoveAll(defaultEtcdV3WorkDir); err != nil {
-		t.Fail()
-	}
+type args struct {
+	client *gxetcd.Client
 }
 
-func TestListener(t *testing.T) {
-
+func TestNewEventListener(t *testing.T) {
 	tests := []struct {
-		input struct {
-			k string
-			v string
-		}
+		name string
+		args args
+		want *EventListener
 	}{
-		{input: struct {
-			k string
-			v string
-		}{k: "/dubbo/", v: changedData}},
-	}
-	SetUpEtcdServer(t)
-	c, err := gxetcd.NewClient("test", []string{"localhost:2381"}, time.Second, 1)
-	assert.NoError(t, err)
-
-	listener := NewEventListener(c)
-	dataListener := &mockDataListener{client: c, changedData: changedData, rc: make(chan remoting.Event)}
-	listener.ListenServiceEvent("/dubbo/", dataListener)
-
-	// NOTICE:  direct listen will lose create msg
-	time.Sleep(time.Second)
-	for _, tc := range tests {
-
-		k := tc.input.k
-		v := tc.input.v
-		if err := c.Update(k, v); err != nil {
-			t.Fatal(err)
-		}
-
+		{
+			name: "test",
+			args: args{
+				client: nil,
+			},
+			want: NewEventListener(nil),
+		},
 	}
-	msg := <-dataListener.rc
-	assert.Equal(t, changedData, msg.Content)
-	ClearEtcdServer(t)
-}
-
-type mockDataListener struct {
-	eventList   []remoting.Event
-	client      *gxetcd.Client
-	changedData string
-
-	rc chan remoting.Event
-}
-
-func (m *mockDataListener) DataChange(eventType remoting.Event) bool {
-	m.eventList = append(m.eventList, eventType)
-	if eventType.Content == m.changedData {
-		m.rc <- eventType
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := NewEventListener(tt.args.client); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("NewEventListener() = %v, want %v", got, tt.want)
+			}
+		})
 	}
-	return true
 }
diff --git a/remoting/nacos/builder_test.go b/remoting/nacos/builder_test.go
index 2fdfa10e1..267d25f2b 100644
--- a/remoting/nacos/builder_test.go
+++ b/remoting/nacos/builder_test.go
@@ -19,11 +19,17 @@ package nacos
 
 import (
 	"net/url"
+	"reflect"
 	"testing"
-	"time"
 )
 
 import (
+	"github.com/agiledragon/gomonkey"
+
+	nacosClient "github.com/dubbogo/gost/database/kv/nacos"
+
+	nacosConstant "github.com/nacos-group/nacos-sdk-go/common/constant"
+
 	"github.com/stretchr/testify/assert"
 )
 
@@ -33,125 +39,169 @@ import (
 	"dubbo.apache.org/dubbo-go/v3/config"
 )
 
-func TestNewNacosClient(t *testing.T) {
-	t.Run("AddressIsNil", func(t *testing.T) {
-		rc := &config.RemoteConfig{}
-		rc.Protocol = "nacos"
-		rc.Username = "nacos"
-		client, err := NewNacosClient(rc)
-
-		// address is nil
-		assert.Nil(t, client)
-		assert.NotNil(t, err)
-	})
-
-	t.Run("InvalidAddress", func(t *testing.T) {
-		rc := &config.RemoteConfig{}
-		rc.Address = "console.nacos.io:80:123"
-		client, err := NewNacosClient(rc)
-		// invalid address
-		assert.Nil(t, client)
-		assert.NotNil(t, err)
-	})
+func getRegURL() *common.URL {
+	regURLMap := url.Values{}
+	regURLMap.Set(constant.NacosNotLoadLocalCache, "true")
+	regURLMap.Set(constant.NacosNamespaceID, "nacos")
+	regURLMap.Set(constant.TimeoutKey, "5s")
+	regURLMap.Set(constant.ClientNameKey, "nacos-client")
+	regURL, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(regURLMap))
 
-	t.Run("Normal", func(t *testing.T) {
-		rc := &config.RemoteConfig{}
-		rc.Address = "console.nacos.io:80"
-		rc.Protocol = "nacos"
-		rc.Timeout = "10s"
-		client, err := NewNacosClient(rc)
-		assert.NotNil(t, client)
-		assert.Nil(t, err)
-	})
-
-	t.Run("NormalHasContextPath", func(t *testing.T) {
-		rc := &config.RemoteConfig{}
-		rc.Address = "console.nacos.io:80/nacos"
-		rc.Protocol = "nacos"
-		client, err := NewNacosClient(rc)
-		assert.NotNil(t, client)
-		assert.Nil(t, err)
-	})
+	return regURL
 }
 
-func TestGetNacosConfig(t *testing.T) {
-	regurl := getRegUrl()
-	sc, cc, err := GetNacosConfig(regurl)
-
-	assert.Nil(t, err)
-	assert.NotNil(t, sc)
-	assert.NotNil(t, cc)
-	assert.Equal(t, cc.TimeoutMs, uint64(5000))
-}
-
-func TestNewNacosConfigClient(t *testing.T) {
-
-	regurl := getRegUrl()
-	client, err := NewNacosConfigClientByUrl(regurl)
-
-	assert.Nil(t, err)
-	assert.NotNil(t, client)
+type args struct {
+	url *common.URL
+	rc  *config.RemoteConfig
 }
 
 func TestNewNacosClientByURL(t *testing.T) {
-	regurl := getRegUrl()
-	client, err := NewNacosClientByURL(regurl)
-
-	assert.Nil(t, err)
-	assert.NotNil(t, client)
-}
-
-func TestTimeoutConfig(t *testing.T) {
-	regurlMap := url.Values{}
-	regurlMap.Set(constant.NacosNotLoadLocalCache, "true")
-	// regurlMap.Set(constant.NacosUsername, "nacos")
-	// regurlMap.Set(constant.NacosPassword, "nacos")
-	regurlMap.Set(constant.NacosNamespaceID, "nacos")
-
-	t.Run("default timeout", func(t *testing.T) {
-		newURL, _ := common.NewURL("registry://console.nacos.io:80", common.WithParams(regurlMap))
-
-		_, cc, err := GetNacosConfig(newURL)
-		assert.Nil(t, err)
-
-		assert.Equal(t, cc.TimeoutMs, uint64(int32(5*time.Second/time.Millisecond)))
-	})
-
-	t.Run("right timeout", func(t *testing.T) {
-
-		regurlMap.Set(constant.NacosTimeout, "7s")
-
-		newURL, _ := common.NewURL("registry://console.nacos.io:80", common.WithParams(regurlMap))
-
-		_, cc, err := GetNacosConfig(newURL)
-		assert.Nil(t, err)
-
-		assert.Equal(t, cc.TimeoutMs, uint64(int32(7*time.Second/time.Millisecond)))
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyFunc(nacosClient.NewNacosNamingClient, func(name string, share bool, sc []nacosConstant.ServerConfig,
+		cc nacosConstant.ClientConfig) (*nacosClient.NacosNamingClient, error) {
+		return &nacosClient.NacosNamingClient{}, nil
 	})
+	defer patches.Reset()
+
+	tests := []struct {
+		name    string
+		args    args
+		want    *nacosClient.NacosNamingClient
+		wantErr bool
+	}{
+		{
+			name: "test",
+			args: args{
+				url: getRegURL(),
+			},
+			want:    &nacosClient.NacosNamingClient{},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := NewNacosClientByURL(tt.args.url)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("NewNacosClientByURL() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("NewNacosClientByURL() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
 
-	t.Run("invalid timeout", func(t *testing.T) {
-		regurlMap.Set(constant.TimeoutKey, "5ab")
-
-		newURL, _ := common.NewURL("registry://console.nacos.io:80", common.WithParams(regurlMap))
-		_, cc, err := GetNacosConfig(newURL)
-		assert.Nil(t, err)
-
-		assert.NotEqual(t, cc.TimeoutMs, uint64(int32(3*time.Second/time.Millisecond)))
+func TestNewNacosClient(t *testing.T) {
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyFunc(nacosClient.NewNacosNamingClient, func(name string, share bool, sc []nacosConstant.ServerConfig,
+		cc nacosConstant.ClientConfig) (*nacosClient.NacosNamingClient, error) {
+		return &nacosClient.NacosNamingClient{}, nil
 	})
-
+	defer patches.Reset()
+
+	tests := []struct {
+		name    string
+		args    args
+		want    *nacosClient.NacosNamingClient
+		wantErr bool
+	}{
+		{
+			name: "test",
+			args: args{
+				rc: &config.RemoteConfig{
+					Address:  "test.nacos.io:80/nacos",
+					Protocol: "nacos",
+					Timeout:  "10s",
+					Username: "naocs",
+					Password: "nacos",
+				},
+			},
+			want:    &nacosClient.NacosNamingClient{},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := NewNacosClient(tt.args.rc)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("NewNacosClient() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("NewNacosClient() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
 }
 
-func getRegUrl() *common.URL {
-
-	regurlMap := url.Values{}
-	regurlMap.Set(constant.NacosNotLoadLocalCache, "true")
-	// regurlMap.Set(constant.NacosUsername, "nacos")
-	// regurlMap.Set(constant.NacosPassword, "nacos")
-	regurlMap.Set(constant.NacosNamespaceID, "nacos")
-	regurlMap.Set(constant.TimeoutKey, "5s")
-	regurlMap.Set(constant.ClientNameKey, "nacos-client")
-
-	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParams(regurlMap))
+func TestGetNacosConfig(t *testing.T) {
+	tests := []struct {
+		name    string
+		args    args
+		want    []nacosConstant.ServerConfig
+		want1   nacosConstant.ClientConfig
+		wantErr bool
+	}{
+		{
+			name: "test",
+			args: args{
+				url: getRegURL(),
+			},
+			want: []nacosConstant.ServerConfig{
+				{
+					IpAddr: "test.nacos.io",
+					Port:   80,
+				},
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, got1, err := GetNacosConfig(tt.args.url)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetNacosConfig() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("GetNacosConfig() got = %v, want %v", got, tt.want)
+			}
+			assert.NotNil(t, got1)
+		})
+	}
+}
 
-	return regurl
+func TestNewNacosConfigClientByUrl(t *testing.T) {
+	patches := gomonkey.NewPatches()
+	patches = patches.ApplyFunc(nacosClient.NewNacosNamingClient, func(name string, share bool, sc []nacosConstant.ServerConfig,
+		cc nacosConstant.ClientConfig) (*nacosClient.NacosNamingClient, error) {
+		return &nacosClient.NacosNamingClient{}, nil
+	})
+	defer patches.Reset()
+
+	tests := []struct {
+		name    string
+		args    args
+		want    *nacosClient.NacosConfigClient
+		wantErr bool
+	}{
+		{
+			name: "test",
+			args: args{
+				url: getRegURL(),
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := NewNacosConfigClientByUrl(tt.args.url)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("NewNacosConfigClientByUrl() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			assert.NotNil(t, got)
+		})
+	}
 }