| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package common |
| |
| import ( |
| "context" |
| "reflect" |
| "testing" |
| ) |
| |
| import ( |
| "github.com/stretchr/testify/assert" |
| ) |
| |
| import ( |
| "dubbo.apache.org/dubbo-go/v3/common/constant" |
| ) |
| |
| const ( |
| referenceTestPath = "com.test.Path" |
| referenceTestPathDistinct = "com.test.Path1" |
| testInterfaceName = "testService" |
| testProtocol = "testprotocol" |
| testSuiteMethodExpectedString = "interface {}" |
| ) |
| |
| type TestService struct{} |
| |
| func (s *TestService) MethodOne(ctx context.Context, arg1, arg2, arg3 interface{}) error { |
| return nil |
| } |
| |
| func (s *TestService) MethodTwo(arg1, arg2, arg3 interface{}) (interface{}, error) { |
| return struct{}{}, nil |
| } |
| |
| func (s *TestService) MethodThree() error { |
| return nil |
| } |
| |
| func (s *TestService) Reference() string { |
| return referenceTestPath |
| } |
| |
| func (s *TestService) MethodMapper() map[string]string { |
| return map[string]string{ |
| "MethodTwo": "methodTwo", |
| } |
| } |
| |
| 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{}) (testService, error) { |
| return testService{}, nil |
| } |
| |
| func (s *testService) Method3(ctx context.Context, args []interface{}, rsp *struct{}) { |
| } |
| |
| func (s *testService) Method4(ctx context.Context, args []interface{}, rsp *struct{}) *testService { |
| return nil |
| } |
| |
| func (s *testService) Reference() string { |
| return referenceTestPath |
| } |
| |
| type TestService1 struct{} |
| |
| func (s *TestService1) Reference() string { |
| return referenceTestPathDistinct |
| } |
| |
| func TestServiceMapRegister(t *testing.T) { |
| // lowercase |
| s0 := &testService{} |
| // methods, err := ServiceMap.Register("testporotocol", s0) |
| _, err := ServiceMap.Register(testInterfaceName, "testporotocol", "", "v0", s0) |
| assert.EqualError(t, err, "type testService is not exported") |
| |
| // succ |
| s := &TestService{} |
| methods, err := ServiceMap.Register(testInterfaceName, "testporotocol", "", "v1", s) |
| assert.NoError(t, err) |
| assert.Equal(t, "MethodOne,MethodThree,methodTwo", methods) |
| |
| // repeat |
| _, err = ServiceMap.Register(testInterfaceName, "testporotocol", "", "v1", s) |
| assert.EqualError(t, err, "service already defined: testService:v1") |
| |
| // no method |
| s1 := &TestService1{} |
| _, err = ServiceMap.Register(testInterfaceName, "testporotocol", "", "v2", s1) |
| assert.EqualError(t, err, "type testService:v2 has no exported methods of suitable type") |
| |
| ServiceMap = &serviceMap{ |
| serviceMap: make(map[string]map[string]*Service), |
| interfaceMap: make(map[string][]*Service), |
| } |
| } |
| |
| func TestServiceMapUnRegister(t *testing.T) { |
| s := &TestService{} |
| _, err := ServiceMap.Register("TestService", testProtocol, "", "v1", s) |
| assert.NoError(t, err) |
| assert.NotNil(t, ServiceMap.GetService(testProtocol, "TestService", "", "v1")) |
| assert.Equal(t, 1, len(ServiceMap.GetInterface("TestService"))) |
| |
| err = ServiceMap.UnRegister("", "", ServiceKey("TestService", "", "v1")) |
| assert.EqualError(t, err, "protocol or ServiceKey is nil") |
| |
| err = ServiceMap.UnRegister("", "protocol", ServiceKey("TestService", "", "v1")) |
| assert.EqualError(t, err, "no services for protocol") |
| |
| err = ServiceMap.UnRegister("", testProtocol, ServiceKey("TestService", "", "v0")) |
| assert.EqualError(t, err, "no service for TestService:v0") |
| |
| // success |
| err = ServiceMap.UnRegister("TestService", testProtocol, ServiceKey("TestService", "", "v1")) |
| assert.NoError(t, err) |
| } |
| |
| func TestMethodTypeSuiteContext(t *testing.T) { |
| mt := &MethodType{ctxType: reflect.TypeOf(context.TODO())} |
| ctx := context.Background() |
| key := constant.DubboCtxKey("key") |
| ctx = context.WithValue(ctx, key, "value") |
| assert.Equal(t, reflect.ValueOf(ctx), mt.SuiteContext(ctx)) |
| } |
| |
| func TestSuiteMethod(t *testing.T) { |
| 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 {}, interface {}, interface {}) error", method.Type.String()) |
| at := methodType.ArgsType() |
| assert.Equal(t, testSuiteMethodExpectedString, at[0].String()) |
| assert.Equal(t, testSuiteMethodExpectedString, at[1].String()) |
| assert.Equal(t, testSuiteMethodExpectedString, at[2].String()) |
| ct := methodType.CtxType() |
| assert.Equal(t, "context.Context", ct.String()) |
| rt := methodType.ReplyType() |
| assert.Nil(t, rt) |
| |
| method, ok = reflect.TypeOf(s).MethodByName("MethodTwo") |
| assert.True(t, ok) |
| methodType = suiteMethod(method) |
| method = methodType.Method() |
| assert.Equal(t, "func(*common.TestService, interface {}, interface {}, interface {}) (interface {}, error)", method.Type.String()) |
| at = methodType.ArgsType() |
| assert.Equal(t, testSuiteMethodExpectedString, at[0].String()) |
| assert.Equal(t, testSuiteMethodExpectedString, at[1].String()) |
| assert.Equal(t, testSuiteMethodExpectedString, at[2].String()) |
| assert.Nil(t, methodType.CtxType()) |
| rt = methodType.ReplyType() |
| assert.Equal(t, testSuiteMethodExpectedString, rt.String()) |
| |
| method, ok = reflect.TypeOf(s).MethodByName("MethodThree") |
| assert.True(t, ok) |
| methodType = suiteMethod(method) |
| method = methodType.Method() |
| assert.Equal(t, "func(*common.TestService) error", method.Type.String()) |
| at = methodType.ArgsType() |
| assert.Equal(t, 0, len(at)) |
| assert.Nil(t, methodType.CtxType()) |
| rt = methodType.ReplyType() |
| assert.Nil(t, rt) |
| |
| // wrong number of in return |
| s1 := &testService{} |
| method, ok = reflect.TypeOf(s1).MethodByName("Reference") |
| 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) |
| |
| // Reply not exported |
| method, ok = reflect.TypeOf(s1).MethodByName("Method2") |
| assert.True(t, ok) |
| methodType = suiteMethod(method) |
| assert.Nil(t, methodType) |
| |
| // no return |
| method, ok = reflect.TypeOf(s1).MethodByName("Method3") |
| assert.True(t, ok) |
| methodType = suiteMethod(method) |
| assert.Nil(t, methodType) |
| |
| // return value is not error |
| method, ok = reflect.TypeOf(s1).MethodByName("Method4") |
| assert.True(t, ok) |
| methodType = suiteMethod(method) |
| assert.Nil(t, methodType) |
| } |