diff --git a/common/proxy/proxy.go b/common/proxy/proxy.go index d511bc93cf0982cbaa2dfea6d63f26136943ad7b..8a2b65c6bf71271be77923da7baf766a770ea415 100644 --- a/common/proxy/proxy.go +++ b/common/proxy/proxy.go @@ -53,18 +53,26 @@ func (p *Proxy) Implement(v common.RPCService) { makeDubboCallProxy := func(methodName string, outs []reflect.Type) func(in []reflect.Value) []reflect.Value { return func(in []reflect.Value) []reflect.Value { - + var ( + err error + inv *invocation_impl.RPCInvocation + ) if methodName == "Echo" { methodName = "$echo" } - inv := invocation_impl.NewRPCInvocationForConsumer(methodName, nil, in[1].Interface().([]interface{}), in[2].Interface(), p.callBack, common.URL{}, nil) + if len(in) == 2 { + inv = invocation_impl.NewRPCInvocationForConsumer(methodName, nil, in[0].Interface().([]interface{}), in[1].Interface(), p.callBack, common.URL{}, nil) + } + if len(in) == 3 { + inv = invocation_impl.NewRPCInvocationForConsumer(methodName, nil, in[1].Interface().([]interface{}), in[2].Interface(), p.callBack, common.URL{}, nil) + } for k, v := range p.attachments { inv.SetAttachments(k, v) } result := p.invoke.Invoke(inv) - var err error + err = result.Error() log.Info("[makeDubboCallProxy] err: %v", err) return []reflect.Value{reflect.ValueOf(&err).Elem()} @@ -76,20 +84,19 @@ func (p *Proxy) Implement(v common.RPCService) { t := typeOf.Field(i) f := valueOfElem.Field(i) if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() { - - if t.Type.NumIn() != 3 && t.Type.NumIn() != 4 { + if t.Type.NumIn() != 2 && t.Type.NumIn() != 3 { log.Warn("method %s of mtype %v has wrong number of in parameters %d; needs exactly 3/4", t.Name, t.Type.String(), t.Type.NumIn()) continue } - if t.Type.NumIn() == 3 && t.Type.In(2).Kind() != reflect.Ptr { - log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(2)) + if t.Type.NumIn() == 2 && t.Type.In(1).Kind() != reflect.Ptr { + log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(1)) continue } - if t.Type.NumIn() == 4 && t.Type.In(3).Kind() != reflect.Ptr { - log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(3)) + if t.Type.NumIn() == 3 && t.Type.In(2).Kind() != reflect.Ptr { + log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(2)) continue } diff --git a/common/proxy/proxy_test.go b/common/proxy/proxy_test.go index 2335fa3c551efa9b9fd9c6d1c27f8f6e4a96d330..73a3fb8ba92bd673cfb8f1d89f04b0f245ed8bf5 100644 --- a/common/proxy/proxy_test.go +++ b/common/proxy/proxy_test.go @@ -34,7 +34,7 @@ func TestProxy_Implement(t *testing.T) { return errors.New("errors") }} p.Implement(s) - err := s.MethodOne(nil, nil, nil) + err := p.Get().(*TestService).MethodOne(nil, nil, nil) assert.NoError(t, err) // inherit & lowercase @@ -54,12 +54,11 @@ func TestProxy_Implement(t *testing.T) { // args number type S2 struct { TestService - MethodOne func(context.Context, []interface{}) error + MethodOne func([]interface{}) error } s2 := &S2{TestService: *s} p.Implement(s2) assert.Nil(t, s2.MethodOne) - //assert.EqualError(t, err, "method MethodOne of mtype func(context.Context, []interface {}) error has wrong number of in parameters 2; needs exactly 3/4") // returns number type S3 struct { @@ -69,7 +68,6 @@ func TestProxy_Implement(t *testing.T) { s3 := &S3{TestService: *s} p.Implement(s3) assert.Nil(t, s3.MethodOne) - //assert.EqualError(t, err, "method \"MethodOne\" has 2 out parameters; needs exactly 1") // returns type type S4 struct { @@ -79,9 +77,8 @@ func TestProxy_Implement(t *testing.T) { s4 := &S4{TestService: *s} p.Implement(s4) assert.Nil(t, s4.MethodOne) - //assert.EqualError(t, err, "return type interface {} of method \"MethodOne\" is not error") - // reply type + // reply type for number 3 type S5 struct { TestService MethodOne func(context.Context, []interface{}, interface{}) error @@ -89,6 +86,13 @@ func TestProxy_Implement(t *testing.T) { s5 := &S5{TestService: *s} p.Implement(s5) assert.Nil(t, s5.MethodOne) - //assert.EqualError(t, err, "reply type of method \"MethodOne\" is not a pointer interface {}") + // reply type for number 2 + type S6 struct { + TestService + MethodOne func([]interface{}, interface{}) error + } + s6 := &S6{TestService: *s} + p.Implement(s6) + assert.Nil(t, s5.MethodOne) } diff --git a/common/rpc_service_test.go b/common/rpc_service_test.go index 768c83ce47f2fa4915a47a216ed2b79bf3e813bd..6d72bf5e56f4eefe1404f92555dcb7fb91265d9f 100644 --- a/common/rpc_service_test.go +++ b/common/rpc_service_test.go @@ -2,6 +2,7 @@ package common import ( "context" + "reflect" "testing" ) @@ -15,12 +16,10 @@ type TestService struct { func (s *TestService) MethodOne(ctx context.Context, args []interface{}, rsp *struct{}) error { return nil } - -func (s *TestService) MethodTwo(ctx context.Context, args []interface{}, rsp *struct{}) error { +func (s *TestService) MethodTwo(args []interface{}, rsp *struct{}) error { return nil } - func (s *TestService) Service() string { return "com.test.Path" } @@ -28,9 +27,132 @@ func (s *TestService) Version() string { return "" } +type testService struct { +} + +func (s *testService) Method1(ctx context.Context, args testService, rsp *struct{}) error { + return nil +} +func (s *testService) Method2(ctx context.Context, args []interface{}, rsp struct{}) error { + return nil +} +func (s *testService) Method3(ctx context.Context, args []interface{}, rsp *testService) error { + return nil +} +func (s *testService) Method4(ctx context.Context, args []interface{}, rsp *struct{}) { +} +func (s *testService) Method5(ctx context.Context, args []interface{}, rsp *struct{}) *testService { + return nil +} +func (s *testService) Service() string { + return "com.test.Path" +} +func (s *testService) Version() string { + return "" +} + +type TestService1 struct { +} + +func (s *TestService1) Service() string { + return "com.test.Path1" +} +func (s *TestService1) Version() string { + return "" +} + func TestServiceMap_Register(t *testing.T) { + // lowercase + s0 := &testService{} + methods, err := ServiceMap.Register("testporotocol", s0) + assert.EqualError(t, err, "type testService is not exported") + + // succ s := &TestService{} - methods, err := ServiceMap.Register("testporotocol", s) + methods, err = ServiceMap.Register("testporotocol", s) assert.NoError(t, err) assert.Equal(t, "MethodOne,MethodTwo", methods) + + // repeat + methods, err = ServiceMap.Register("testporotocol", s) + assert.EqualError(t, err, "service already defined: com.test.Path") + + // no method + s1 := &TestService1{} + methods, err = ServiceMap.Register("testporotocol", s1) + assert.EqualError(t, err, "type com.test.Path1 has no exported methods of suitable type") +} + +func TestMethodType_SuiteContext(t *testing.T) { + mt := &MethodType{ctxType: reflect.TypeOf(context.TODO())} + c := context.TODO() + c = context.WithValue(c, "key", "value") + assert.Equal(t, reflect.ValueOf(c), mt.SuiteContext(c)) + + assert.Equal(t, reflect.Zero(mt.ctxType), mt.SuiteContext(nil)) +} + +func TestSuiteMethod(t *testing.T) { + // 4 + s := &TestService{} + method, ok := reflect.TypeOf(s).MethodByName("MethodOne") + assert.True(t, ok) + methodType := suiteMethod(method) + method = methodType.Method() + assert.Equal(t, "func(*common.TestService, context.Context, []interface {}, *struct {}) error", method.Type.String()) + at := methodType.ArgType() + assert.Equal(t, "[]interface {}", at.String()) + ct := methodType.CtxType() + assert.Equal(t, "context.Context", ct.String()) + rt := methodType.ReplyType() + assert.Equal(t, "*struct {}", rt.String()) + + // 3 + method, ok = reflect.TypeOf(s).MethodByName("MethodTwo") + assert.True(t, ok) + methodType = suiteMethod(method) + method = methodType.Method() + assert.Equal(t, "func(*common.TestService, []interface {}, *struct {}) error", method.Type.String()) + at = methodType.ArgType() + assert.Equal(t, "[]interface {}", at.String()) + assert.Nil(t, methodType.CtxType()) + rt = methodType.ReplyType() + assert.Equal(t, "*struct {}", rt.String()) + + // wrong number of in parameters + s1 := &testService{} + method, ok = reflect.TypeOf(s1).MethodByName("Version") + assert.True(t, ok) + methodType = suiteMethod(method) + assert.Nil(t, methodType) + + // args not exported + method, ok = reflect.TypeOf(s1).MethodByName("Method1") + assert.True(t, ok) + methodType = suiteMethod(method) + assert.Nil(t, methodType) + + // replyType != Ptr + method, ok = reflect.TypeOf(s1).MethodByName("Method2") + assert.True(t, ok) + methodType = suiteMethod(method) + assert.Nil(t, methodType) + + // Reply not exported + method, ok = reflect.TypeOf(s1).MethodByName("Method3") + assert.True(t, ok) + methodType = suiteMethod(method) + assert.Nil(t, methodType) + + // no return + method, ok = reflect.TypeOf(s1).MethodByName("Method4") + assert.True(t, ok) + methodType = suiteMethod(method) + assert.Nil(t, methodType) + + // return value is not error + method, ok = reflect.TypeOf(s1).MethodByName("Method5") + assert.True(t, ok) + methodType = suiteMethod(method) + assert.Nil(t, methodType) } diff --git a/common/url.go b/common/url.go index a24a03c1f10e447d66a6a5f0bdef5e878d58807d..e67a59e514a71c18751236c9f8cc454fba240cfd 100644 --- a/common/url.go +++ b/common/url.go @@ -216,9 +216,7 @@ func (c URL) String() string { buildString := fmt.Sprintf( "%s://%s:%s@%s:%s%s?", c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path) - for k, v := range c.Params { - buildString += "&" + k + "=" + v[0] - } + buildString += c.Params.Encode() return buildString } @@ -265,7 +263,7 @@ func (c URL) GetMethodParamInt(method string, key string, d int64) int64 { func (c URL) GetMethodParam(method string, key string, d string) string { var r string - if r = c.Params.Get(c.Params.Get("methods." + method + "." + key)); r == "" { + if r = c.Params.Get("methods." + method + "." + key); r == "" { r = d } return r diff --git a/common/url_test.go b/common/url_test.go new file mode 100644 index 0000000000000000000000000000000000000000..336ec9ee7a93111514a72b2afae7683435173459 --- /dev/null +++ b/common/url_test.go @@ -0,0 +1,121 @@ +package common + +import ( + "context" + "net/url" + "testing" +) + +import ( + "github.com/stretchr/testify/assert" +) + +func TestNewURLWithOptions(t *testing.T) { + methods := []string{"Methodone,methodtwo"} + params := url.Values{} + params.Set("key", "value") + u := NewURLWithOptions("com.test.Service", + WithUsername("username"), + WithPassword("password"), + WithProtocol("testprotocol"), + WithIp("127.0.0.1"), + WithPort("8080"), + WithMethods(methods), + WithParams(params), + WithParamsValue("key2", "value2")) + assert.Equal(t, "/com.test.Service", u.Path) + assert.Equal(t, "username", u.Username) + assert.Equal(t, "password", u.Password) + assert.Equal(t, "testprotocol", u.Protocol) + assert.Equal(t, "127.0.0.1", u.Ip) + assert.Equal(t, "8080", u.Port) + assert.Equal(t, methods, u.Methods) + assert.Equal(t, params, u.Params) +} + +func TestURL(t *testing.T) { + u, err := NewURL(context.TODO(), "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ + "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ + "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ + "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ + "side=provider&timeout=3000×tamp=1556509797245") + assert.NoError(t, err) + + assert.Equal(t, "/com.ikurento.user.UserProvider", u.Path) + assert.Equal(t, "127.0.0.1:20000", u.Location) + assert.Equal(t, "dubbo", u.Protocol) + assert.Equal(t, "127.0.0.1", u.Ip) + assert.Equal(t, "20000", u.Port) + assert.Equal(t, URL{}.Methods, u.Methods) + assert.Equal(t, "", u.Username) + assert.Equal(t, "", u.Password) + assert.Equal(t, "anyhost=true&application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-"+ + "provider-golang-1.0.0&environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%"+ + "2C&module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&side=provider&timeout=3000&t"+ + "imestamp=1556509797245", u.Params.Encode()) + + assert.Equal(t, "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&application=BDTServi"+ + "ce&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&environment=dev&interface=com.ikure"+ + "nto.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&module=dubbogo+user-info+server&org=ikurento.com&owner="+ + "ZX&pid=1447&revision=0.0.1&side=provider&timeout=3000×tamp=1556509797245", u.String()) +} + +func TestURL_URLEqual(t *testing.T) { + u1, err := NewURL(context.TODO(), "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0") + assert.NoError(t, err) + u2, err := NewURL(context.TODO(), "dubbo://:@127.0.0.2:20001/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0") + assert.NoError(t, err) + assert.True(t, u1.URLEqual(u2)) + + u3, err := NewURL(context.TODO(), "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0") + assert.NoError(t, err) + assert.False(t, u1.URLEqual(u3)) +} + +func TestURL_GetParam(t *testing.T) { + params := url.Values{} + params.Set("key", "value") + u := URL{baseUrl: baseUrl{Params: params}} + v := u.GetParam("key", "default") + assert.Equal(t, "value", v) + + u = URL{} + v = u.GetParam("key", "default") + assert.Equal(t, "default", v) +} + +func TestURL_GetParamInt(t *testing.T) { + params := url.Values{} + params.Set("key", "3") + u := URL{baseUrl: baseUrl{Params: params}} + v := u.GetParamInt("key", 1) + assert.Equal(t, int64(3), v) + + u = URL{} + v = u.GetParamInt("key", 1) + assert.Equal(t, int64(1), v) +} + +func TestURL_GetMethodParamInt(t *testing.T) { + params := url.Values{} + params.Set("methods.GetValue.timeout", "3") + u := URL{baseUrl: baseUrl{Params: params}} + v := u.GetMethodParamInt("GetValue", "timeout", 1) + assert.Equal(t, int64(3), v) + + u = URL{} + v = u.GetMethodParamInt("GetValue", "timeout", 1) + assert.Equal(t, int64(1), v) +} + +func TestURL_GetMethodParam(t *testing.T) { + params := url.Values{} + params.Set("methods.GetValue.timeout", "3s") + u := URL{baseUrl: baseUrl{Params: params}} + v := u.GetMethodParam("GetValue", "timeout", "1s") + assert.Equal(t, "3s", v) + + u = URL{} + v = u.GetMethodParam("GetValue", "timeout", "1s") + assert.Equal(t, "1s", v) +}