Skip to content

Commit

Permalink
add metadata client test case
Browse files Browse the repository at this point in the history
  • Loading branch information
FoghostCn committed Apr 20, 2024
1 parent ded7253 commit 28e44c4
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 36 deletions.
41 changes: 13 additions & 28 deletions metadata/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ package metadata
import (
"context"
"encoding/json"
"time"
)

import (
Expand All @@ -37,47 +36,33 @@ import (
"dubbo.apache.org/dubbo-go/v3/registry"
)

const metadataProxyDefaultTimeout = 5000
const defaultTimeout = "5s" // s

// GetMetadataFromMetadataReport test depends on dubbo protocol, if dubbo not dependent on config package, can move to metadata dir
func GetMetadataFromMetadataReport(revision string, instance registry.ServiceInstance) (*info.MetadataInfo, error) {
report := GetMetadataReport()
if report == nil {
return nil, perrors.New("no metadata report instance found,please check ")
}
return report.GetAppMetadata(instance.GetServiceName(), revision)
}

func GetMetadataFromRpc(revision string, instance registry.ServiceInstance) (*info.MetadataInfo, error) {
service, destroy, err := createRpcClient(instance)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(metadataProxyDefaultTimeout))
defer cancel()
defer destroy()
return service.GetMetadataInfo(ctx, revision)
}

type remoteMetadataService struct {
GetMetadataInfo func(context context.Context, revision string) (*info.MetadataInfo, error) `dubbo:"getMetadataInfo"`
}

func createRpcClient(instance registry.ServiceInstance) (*remoteMetadataService, func(), error) {
params := getMetadataServiceUrlParams(instance.GetMetadata()[constant.MetadataServiceURLParamsPropertyName])
url := buildMetadataServiceURL(instance.GetServiceName(), instance.GetHost(), params)
return createRpcClientByUrl(url)
}

func createRpcClientByUrl(url *common.URL) (*remoteMetadataService, func(), error) {
url.SetParam(constant.TimeoutKey, defaultTimeout)
rpcService := &remoteMetadataService{}
invoker := extension.GetProtocol(constant.Dubbo).Refer(url)
if invoker == nil {
return nil, nil, perrors.New("create invoker error, can not connect to the metadata report server: " + url.Ip + ":" + url.Port)
return nil, perrors.New("create invoker error, can not connect to the metadata report server: " + url.Ip + ":" + url.Port)
}
proxy := extension.GetProxyFactory(constant.DefaultKey).GetProxy(invoker, url)
proxy.Implement(rpcService)
destroy := func() {
invoker.Destroy()
}
return rpcService, destroy, nil
defer invoker.Destroy()
return rpcService.GetMetadataInfo(context.TODO(), revision)
}

type remoteMetadataService struct {
GetMetadataInfo func(context context.Context, revision string) (*info.MetadataInfo, error) `dubbo:"getMetadataInfo"`
}

// buildMetadataServiceURL will use standard format to build the metadata service url.
Expand Down Expand Up @@ -108,7 +93,7 @@ func getMetadataServiceUrlParams(jsonStr string) map[string]string {
if len(jsonStr) > 0 {
err := json.Unmarshal([]byte(jsonStr), &res)
if err != nil {
logger.Errorf("could not parse the metadata service url parameters to map", err)
logger.Errorf("could not parse the metadata service url parameters '%s' to map", jsonStr)
}
}
return res
Expand Down
241 changes: 241 additions & 0 deletions metadata/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
package metadata

import (
"context"
"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/info"
"dubbo.apache.org/dubbo-go/v3/protocol"
_ "dubbo.apache.org/dubbo-go/v3/proxy/proxy_factory"
"dubbo.apache.org/dubbo-go/v3/registry"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"testing"
)

var (
ins = &registry.DefaultServiceInstance{
ID: "1",
Metadata: map[string]string{
constant.MetadataServiceURLParamsPropertyName: `{
"application": "dubbo-go",
"group": "BDTService",
"port": "64658",
"protocol": "dubbo",
"version": "1.0.0"
}`,
},
Host: "dubbo.io",
ServiceName: "dubbo-app",
}
metadataInfo = &info.MetadataInfo{
App: "dubbo-app",
}
)

func TestGetMetadataFromMetadataReport(t *testing.T) {
t.Run("no report instance", func(t *testing.T) {
_, err := GetMetadataFromMetadataReport("1", ins)
assert.NotNil(t, err)
})
mockReport := new(mockMetadataReport)
defer mockReport.AssertExpectations(t)
instances["default"] = mockReport
t.Run("normal", func(t *testing.T) {
mockReport.On("GetAppMetadata").Return(metadataInfo, nil).Once()
got, err := GetMetadataFromMetadataReport("1", ins)
assert.Nil(t, err)
assert.Equal(t, metadataInfo, got)
})
t.Run("error", func(t *testing.T) {
mockReport.On("GetAppMetadata").Return(metadataInfo, errors.New("mock error")).Once()
_, err := GetMetadataFromMetadataReport("1", ins)
assert.NotNil(t, err)
})
}

func TestGetMetadataFromRpc(t *testing.T) {
mockInvoker := new(mockInvoker)
defer mockInvoker.AssertExpectations(t)
mockProtocol := new(mockProtocol)
extension.SetProtocol("dubbo", func() protocol.Protocol {
return mockProtocol
})

result := &protocol.RPCResult{
Attrs: map[string]interface{}{},
Err: nil,
Rest: metadataInfo,
}
t.Run("normal", func(t *testing.T) {
mockProtocol.On("Refer").Return(mockInvoker).Once()
mockInvoker.On("Invoke").Return(result).Once()
mockInvoker.On("Destroy").Once()
metadata, err := GetMetadataFromRpc("111", ins)
assert.Nil(t, err)
assert.Equal(t, metadata, result.Rest)
})
t.Run("refer error", func(t *testing.T) {
mockProtocol.On("Refer").Return(nil).Once()
_, err := GetMetadataFromRpc("111", ins)
assert.NotNil(t, err)
})
t.Run("invoke timeout", func(t *testing.T) {
mockProtocol.On("Refer").Return(mockInvoker).Once()
mockInvoker.On("Invoke").Return(&protocol.RPCResult{
Attrs: map[string]interface{}{},
Err: errors.New("timeout error"),
Rest: metadataInfo,
}).Once()
mockInvoker.On("Destroy").Once()
_, err := GetMetadataFromRpc("111", ins)
assert.NotNil(t, err)
})
}

func Test_buildMetadataServiceURL(t *testing.T) {
type args struct {
serviceName string
host string
params map[string]string
}
tests := []struct {
name string
args args
want *common.URL
}{
{
name: "normal",
args: args{
serviceName: "dubbo-app",
host: "dubbo.io",
params: map[string]string{
constant.ProtocolKey: "dubbo",
constant.PortKey: "3000",
},
},
want: common.NewURLWithOptions(
common.WithIp("dubbo.io"),
common.WithProtocol("dubbo"),
common.WithPath(constant.MetadataServiceName),
common.WithProtocol("dubbo"),
common.WithPort("3000"),
common.WithParams(map[string][]string{
constant.ProtocolKey: {"dubbo"},
constant.PortKey: {"3000"},
}),
common.WithParamsValue(constant.GroupKey, "dubbo-app"),
common.WithParamsValue(constant.InterfaceKey, constant.MetadataServiceName),
),
},
{
name: "no protocol",
args: args{
serviceName: "dubbo-app",
host: "dubbo.io",
params: map[string]string{},
},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, buildMetadataServiceURL(tt.args.serviceName, tt.args.host, tt.args.params), "buildMetadataServiceURL(%v, %v, %v)", tt.args.serviceName, tt.args.host, tt.args.params)
})
}
}

func Test_getMetadataServiceUrlParams(t *testing.T) {
type args struct {
jsonStr string
}
tests := []struct {
name string
args args
want map[string]string
}{
{
name: "normal",
args: args{
jsonStr: `{
"application": "BDTService",
"group": "BDTService",
"port": "64658",
"protocol": "dubbo",
"release": "dubbo-golang-3.0.0",
"timestamp": "1713432877",
"version": "1.0.0"
}`,
},
want: map[string]string{
"application": "BDTService",
"group": "BDTService",
"port": "64658",
"protocol": "dubbo",
"release": "dubbo-golang-3.0.0",
"timestamp": "1713432877",
"version": "1.0.0",
},
},
{
name: "wrong format",
args: args{
jsonStr: "xxx",
},
want: map[string]string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, getMetadataServiceUrlParams(tt.args.jsonStr), "getMetadataServiceUrlParams(%v)", tt.args.jsonStr)
})
}
}

type mockProtocol struct {
mock.Mock
}

func (m mockProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
return nil
}

func (m mockProtocol) Refer(url *common.URL) protocol.Invoker {
args := m.Called()
if args.Get(0) == nil {
return nil
}
return args.Get(0).(protocol.Invoker)
}

func (m mockProtocol) Destroy() {
}

type mockInvoker struct {
mock.Mock
}

func (m mockInvoker) GetURL() *common.URL {
return nil
}

func (m mockInvoker) IsAvailable() bool {
return true
}

func (m mockInvoker) Destroy() {
m.Called()
}

func (m mockInvoker) Invoke(ctx context.Context, inv protocol.Invocation) protocol.Result {
args := m.Mock.Called()
meta := args.Get(0).(protocol.Result).Result().(*info.MetadataInfo)
reply := inv.Reply().(*info.MetadataInfo)
reply.App = meta.App
reply.Tag = meta.Tag
reply.Revision = meta.Revision
reply.Services = meta.Services
return args.Get(0).(protocol.Result)
}
14 changes: 7 additions & 7 deletions metadata/metadata_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (mts *DefaultMetadataService) GetMetadataInfo(revision string) (*info.Metad
if revision == "" {
return nil, nil
}
for _, metadataInfo := range appMetadataInfoMap {
for _, metadataInfo := range registryMetadataInfo {
if metadataInfo.Revision == revision {
return metadataInfo, nil
}
Expand All @@ -109,7 +109,7 @@ func (mts *DefaultMetadataService) GetMetadataInfo(revision string) (*info.Metad
// GetExportedServiceURLs get exported service urls
func (mts *DefaultMetadataService) GetExportedServiceURLs() ([]*common.URL, error) {
urls := make([]*common.URL, 0)
for _, metadataInfo := range appMetadataInfoMap {
for _, metadataInfo := range registryMetadataInfo {
urls = append(urls, metadataInfo.GetExportedServiceURLs()...)
}
return urls, nil
Expand All @@ -127,7 +127,7 @@ func (mts *DefaultMetadataService) GetMetadataServiceURL() (*common.URL, error)

func (mts *DefaultMetadataService) GetSubscribedURLs() ([]*common.URL, error) {
urls := make([]*common.URL, 0)
for _, metadataInfo := range appMetadataInfoMap {
for _, metadataInfo := range registryMetadataInfo {
urls = append(urls, metadataInfo.GetSubscribedURLs()...)
}
return urls, nil
Expand All @@ -141,15 +141,15 @@ func (mts *DefaultMetadataService) MethodMapper() map[string]string {
}
}

// ServiceExporter is the ConfigurableMetadataServiceExporter which implement MetadataServiceExporter interface
type ServiceExporter struct {
// serviceExporter export MetadataService with dubbo protocol
type serviceExporter struct {
opts *Options
service MetadataService
protocolExporter protocol.Exporter
}

// Export will export the metadataService
func (e *ServiceExporter) Export() error {
func (e *serviceExporter) Export() error {
version, _ := e.service.Version()
var port string
if e.opts.port == 0 {
Expand Down Expand Up @@ -199,6 +199,6 @@ func randomPort() string {
}

// UnExport will unExport the metadataService
func (e *ServiceExporter) UnExport() {
func (e *serviceExporter) UnExport() {
e.protocolExporter.UnExport()
}
2 changes: 1 addition & 1 deletion metadata/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (opts *Options) Init() error {
var err error
exportOnce.Do(func() {
if opts.metadataType != constant.RemoteMetadataStorageType {
exporter := &ServiceExporter{service: metadataService, opts: opts}
exporter := &serviceExporter{service: metadataService, opts: opts}
defer func() {
// TODO remove this recover func,this just to avoid some unit test failed,this will not happen in user side mostly
// config test -> metadata exporter -> dubbo protocol/remoting -> config,cycle import will occur
Expand Down

0 comments on commit 28e44c4

Please sign in to comment.