dubbo.apache.org/dubbo-go/v3@v3.1.1/common/rpc_service_test.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package common
    19  
    20  import (
    21  	"context"
    22  	"reflect"
    23  	"testing"
    24  )
    25  
    26  import (
    27  	"github.com/stretchr/testify/assert"
    28  )
    29  
    30  import (
    31  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    32  )
    33  
    34  const (
    35  	referenceTestPath             = "com.test.Path"
    36  	referenceTestPathDistinct     = "com.test.Path1"
    37  	testInterfaceName             = "testService"
    38  	testProtocol                  = "testprotocol"
    39  	testSuiteMethodExpectedString = "interface {}"
    40  )
    41  
    42  type TestService struct{}
    43  
    44  func (s *TestService) MethodOne(ctx context.Context, arg1, arg2, arg3 interface{}) error {
    45  	return nil
    46  }
    47  
    48  func (s *TestService) MethodTwo(arg1, arg2, arg3 interface{}) (interface{}, error) {
    49  	return struct{}{}, nil
    50  }
    51  
    52  func (s *TestService) MethodThree() error {
    53  	return nil
    54  }
    55  
    56  func (s *TestService) Reference() string {
    57  	return referenceTestPath
    58  }
    59  
    60  func (s *TestService) MethodMapper() map[string]string {
    61  	return map[string]string{
    62  		"MethodTwo": "methodTwo",
    63  	}
    64  }
    65  
    66  type testService struct{}
    67  
    68  func (s *testService) Method1(ctx context.Context, args testService, rsp *struct{}) error {
    69  	return nil
    70  }
    71  
    72  func (s *testService) Method2(ctx context.Context, args []interface{}) (testService, error) {
    73  	return testService{}, nil
    74  }
    75  
    76  func (s *testService) Method3(ctx context.Context, args []interface{}, rsp *struct{}) {
    77  }
    78  
    79  func (s *testService) Method4(ctx context.Context, args []interface{}, rsp *struct{}) *testService {
    80  	return nil
    81  }
    82  
    83  func (s *testService) Reference() string {
    84  	return referenceTestPath
    85  }
    86  
    87  type TestService1 struct{}
    88  
    89  func (s *TestService1) Reference() string {
    90  	return referenceTestPathDistinct
    91  }
    92  
    93  func TestServiceMapRegister(t *testing.T) {
    94  	// lowercase
    95  	s0 := &testService{}
    96  	// methods, err := ServiceMap.Register("testporotocol", s0)
    97  	_, err := ServiceMap.Register(testInterfaceName, "testporotocol", "", "v0", s0)
    98  	assert.EqualError(t, err, "type testService is not exported")
    99  
   100  	// succ
   101  	s := &TestService{}
   102  	methods, err := ServiceMap.Register(testInterfaceName, "testporotocol", "", "v1", s)
   103  	assert.NoError(t, err)
   104  	assert.Equal(t, "MethodOne,MethodThree,methodTwo", methods)
   105  
   106  	// repeat
   107  	_, err = ServiceMap.Register(testInterfaceName, "testporotocol", "", "v1", s)
   108  	assert.EqualError(t, err, "service already defined: testService:v1")
   109  
   110  	// no method
   111  	s1 := &TestService1{}
   112  	_, err = ServiceMap.Register(testInterfaceName, "testporotocol", "", "v2", s1)
   113  	assert.EqualError(t, err, "type testService:v2 has no exported methods of suitable type")
   114  
   115  	ServiceMap = &serviceMap{
   116  		serviceMap:   make(map[string]map[string]*Service),
   117  		interfaceMap: make(map[string][]*Service),
   118  	}
   119  }
   120  
   121  func TestServiceMapUnRegister(t *testing.T) {
   122  	s := &TestService{}
   123  	_, err := ServiceMap.Register("TestService", testProtocol, "", "v1", s)
   124  	assert.NoError(t, err)
   125  	assert.NotNil(t, ServiceMap.GetService(testProtocol, "TestService", "", "v1"))
   126  	assert.Equal(t, 1, len(ServiceMap.GetInterface("TestService")))
   127  
   128  	err = ServiceMap.UnRegister("", "", ServiceKey("TestService", "", "v1"))
   129  	assert.EqualError(t, err, "protocol or ServiceKey is nil")
   130  
   131  	err = ServiceMap.UnRegister("", "protocol", ServiceKey("TestService", "", "v1"))
   132  	assert.EqualError(t, err, "no services for protocol")
   133  
   134  	err = ServiceMap.UnRegister("", testProtocol, ServiceKey("TestService", "", "v0"))
   135  	assert.EqualError(t, err, "no service for TestService:v0")
   136  
   137  	// success
   138  	err = ServiceMap.UnRegister("TestService", testProtocol, ServiceKey("TestService", "", "v1"))
   139  	assert.NoError(t, err)
   140  }
   141  
   142  func TestMethodTypeSuiteContext(t *testing.T) {
   143  	mt := &MethodType{ctxType: reflect.TypeOf(context.TODO())}
   144  	ctx := context.Background()
   145  	key := constant.DubboCtxKey("key")
   146  	ctx = context.WithValue(ctx, key, "value")
   147  	assert.Equal(t, reflect.ValueOf(ctx), mt.SuiteContext(ctx))
   148  }
   149  
   150  func TestSuiteMethod(t *testing.T) {
   151  	s := &TestService{}
   152  	method, ok := reflect.TypeOf(s).MethodByName("MethodOne")
   153  	assert.True(t, ok)
   154  	methodType := suiteMethod(method)
   155  	method = methodType.Method()
   156  	assert.Equal(t, "func(*common.TestService, context.Context, interface {}, interface {}, interface {}) error", method.Type.String())
   157  	at := methodType.ArgsType()
   158  	assert.Equal(t, testSuiteMethodExpectedString, at[0].String())
   159  	assert.Equal(t, testSuiteMethodExpectedString, at[1].String())
   160  	assert.Equal(t, testSuiteMethodExpectedString, at[2].String())
   161  	ct := methodType.CtxType()
   162  	assert.Equal(t, "context.Context", ct.String())
   163  	rt := methodType.ReplyType()
   164  	assert.Nil(t, rt)
   165  
   166  	method, ok = reflect.TypeOf(s).MethodByName("MethodTwo")
   167  	assert.True(t, ok)
   168  	methodType = suiteMethod(method)
   169  	method = methodType.Method()
   170  	assert.Equal(t, "func(*common.TestService, interface {}, interface {}, interface {}) (interface {}, error)", method.Type.String())
   171  	at = methodType.ArgsType()
   172  	assert.Equal(t, testSuiteMethodExpectedString, at[0].String())
   173  	assert.Equal(t, testSuiteMethodExpectedString, at[1].String())
   174  	assert.Equal(t, testSuiteMethodExpectedString, at[2].String())
   175  	assert.Nil(t, methodType.CtxType())
   176  	rt = methodType.ReplyType()
   177  	assert.Equal(t, testSuiteMethodExpectedString, rt.String())
   178  
   179  	method, ok = reflect.TypeOf(s).MethodByName("MethodThree")
   180  	assert.True(t, ok)
   181  	methodType = suiteMethod(method)
   182  	method = methodType.Method()
   183  	assert.Equal(t, "func(*common.TestService) error", method.Type.String())
   184  	at = methodType.ArgsType()
   185  	assert.Equal(t, 0, len(at))
   186  	assert.Nil(t, methodType.CtxType())
   187  	rt = methodType.ReplyType()
   188  	assert.Nil(t, rt)
   189  
   190  	// wrong number of in return
   191  	s1 := &testService{}
   192  	method, ok = reflect.TypeOf(s1).MethodByName("Reference")
   193  	assert.True(t, ok)
   194  	methodType = suiteMethod(method)
   195  	assert.Nil(t, methodType)
   196  
   197  	// args not exported
   198  	method, ok = reflect.TypeOf(s1).MethodByName("Method1")
   199  	assert.True(t, ok)
   200  	methodType = suiteMethod(method)
   201  	assert.Nil(t, methodType)
   202  
   203  	// Reply not exported
   204  	method, ok = reflect.TypeOf(s1).MethodByName("Method2")
   205  	assert.True(t, ok)
   206  	methodType = suiteMethod(method)
   207  	assert.Nil(t, methodType)
   208  
   209  	// no return
   210  	method, ok = reflect.TypeOf(s1).MethodByName("Method3")
   211  	assert.True(t, ok)
   212  	methodType = suiteMethod(method)
   213  	assert.Nil(t, methodType)
   214  
   215  	// return value is not error
   216  	method, ok = reflect.TypeOf(s1).MethodByName("Method4")
   217  	assert.True(t, ok)
   218  	methodType = suiteMethod(method)
   219  	assert.Nil(t, methodType)
   220  }
   221  
   222  type ServiceWithoutRef struct{}
   223  
   224  func TestGetReference(t *testing.T) {
   225  	s0 := &TestService{}
   226  	ref0 := GetReference(s0)
   227  	assert.Equal(t, referenceTestPath, ref0)
   228  
   229  	//s1 := TestService{}
   230  	//ref1 := GetReference(s1)
   231  	//assert.Equal(t, referenceTestPath, ref1)
   232  
   233  	s2 := &struct {
   234  		TestService
   235  	}{}
   236  	ref2 := GetReference(s2)
   237  	assert.Equal(t, referenceTestPath, ref2)
   238  
   239  	expectedReference := "ServiceWithoutRef"
   240  	s3 := &ServiceWithoutRef{}
   241  	ref3 := GetReference(s3)
   242  	assert.Equal(t, expectedReference, ref3)
   243  
   244  	s4 := ServiceWithoutRef{}
   245  	ref4 := GetReference(s4)
   246  	assert.Equal(t, expectedReference, ref4)
   247  
   248  	s5 := &struct {
   249  		ServiceWithoutRef
   250  	}{}
   251  	ref5 := GetReference(s5)
   252  	assert.Equal(t, expectedReference, ref5)
   253  }