github.com/cloudwego/kitex@v0.9.0/pkg/rpcinfo/remoteinfo/remoteInfo_test.go (about)

     1  /*
     2   * Copyright 2021 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package remoteinfo_test
    18  
    19  import (
    20  	"sync"
    21  	"testing"
    22  
    23  	"github.com/golang/mock/gomock"
    24  
    25  	"github.com/cloudwego/kitex/internal"
    26  	mocksdiscovery "github.com/cloudwego/kitex/internal/mocks/discovery"
    27  	"github.com/cloudwego/kitex/internal/test"
    28  	"github.com/cloudwego/kitex/pkg/discovery"
    29  	"github.com/cloudwego/kitex/pkg/rpcinfo"
    30  	"github.com/cloudwego/kitex/pkg/rpcinfo/remoteinfo"
    31  	"github.com/cloudwego/kitex/pkg/utils"
    32  )
    33  
    34  func TestRemoteInfo(t *testing.T) {
    35  	test.PanicAt(t, func() {
    36  		_ = remoteinfo.NewRemoteInfo(nil, "method")
    37  	}, func(err interface{}) bool {
    38  		e, ok := err.(error)
    39  		return ok && e.Error() == "nil basicInfo"
    40  	})
    41  
    42  	bi := &rpcinfo.EndpointBasicInfo{
    43  		ServiceName: "service",
    44  		Method:      "method0",
    45  		Tags:        map[string]string{"a": "b"},
    46  	}
    47  	ri := remoteinfo.NewRemoteInfo(bi, "method1")
    48  	test.Assert(t, ri != nil)
    49  	test.Assert(t, ri.ServiceName() == "service")
    50  	test.Assert(t, ri.Method() == "method1")
    51  	test.Assert(t, ri.DefaultTag("a", "-") == "b")
    52  	test.Assert(t, ri.DefaultTag("x", "-") == "-")
    53  }
    54  
    55  func TestAsRemoteInfo(t *testing.T) {
    56  	test.Assert(t, remoteinfo.AsRemoteInfo(nil) == nil)
    57  
    58  	ei := rpcinfo.EmptyEndpointInfo()
    59  	test.Assert(t, remoteinfo.AsRemoteInfo(ei) == nil)
    60  
    61  	bi := &rpcinfo.EndpointBasicInfo{
    62  		ServiceName: "service",
    63  		Method:      "method0",
    64  		Tags:        map[string]string{"a": "b", "1": "2"},
    65  	}
    66  	ri := remoteinfo.NewRemoteInfo(bi, "method1")
    67  	ri.SetTagLock("1")
    68  	test.Assert(t, ri.GetInstance() == nil)
    69  
    70  	ei = ri.ImmutableView()
    71  	ri2 := remoteinfo.AsRemoteInfo(ei)
    72  	test.Assert(t, ri2 != nil)
    73  
    74  	ri2.SetServiceName("service2")
    75  	test.Assert(t, ri2.SetTag("a", "aa") == nil)
    76  	test.Assert(t, ri2.SetTag("1", "11") != nil)
    77  
    78  	test.Assert(t, ri.ServiceName() == "service2")
    79  	test.Assert(t, ri.DefaultTag("a", "-") == "aa")
    80  	test.Assert(t, ri.DefaultTag("1", "-") == "2")
    81  	test.Assert(t, ri.GetInstance() == nil)
    82  	test.Assert(t, ri.Address() == nil)
    83  
    84  	ins := discovery.NewInstance("n", "a", 1, nil)
    85  	ri2.SetInstance(ins)
    86  	test.Assert(t, ri.GetInstance() == ins)
    87  	na := ri.Address()
    88  	test.Assert(t, na.Network() == "n" && na.String() == "a")
    89  
    90  	_, ok := ins.(remoteinfo.RefreshableInstance)
    91  	na = utils.NewNetAddr("nnn", "aaa")
    92  	test.Assert(t, ri2.SetRemoteAddr(na) == ok)
    93  	if ok {
    94  		na2 := ri.GetInstance().Address()
    95  		test.Assert(t, na2 != nil)
    96  		test.Assert(t, na2.Network() == "nnn", na2.Network(), na2)
    97  		test.Assert(t, na2.String() == "aaa")
    98  	}
    99  }
   100  
   101  func TestSetTag(t *testing.T) {
   102  	lockKey := "lock"
   103  	unlockKey := "unlock"
   104  	bi := &rpcinfo.EndpointBasicInfo{
   105  		ServiceName: "service",
   106  		Tags:        map[string]string{lockKey: "a", unlockKey: "b"},
   107  	}
   108  	ri := remoteinfo.NewRemoteInfo(bi, "method1")
   109  
   110  	ri.SetTagLock(lockKey)
   111  	val, exist := ri.Tag(lockKey)
   112  	test.Assert(t, val == "a")
   113  	test.Assert(t, exist)
   114  	val, exist = ri.Tag(unlockKey)
   115  	test.Assert(t, val == "b")
   116  	test.Assert(t, exist)
   117  
   118  	// lock key cannot be reset
   119  	ri.SetTag(lockKey, "aa")
   120  	val, _ = ri.Tag(lockKey)
   121  	test.Assert(t, val == "a")
   122  
   123  	// lock key still can be reset with ForceSetTag
   124  	ri.ForceSetTag(lockKey, "aa")
   125  	val, _ = ri.Tag(lockKey)
   126  	test.Assert(t, val == "aa")
   127  
   128  	// unlock key can be reset
   129  	ri.SetTag(unlockKey, "bb")
   130  	val, _ = ri.Tag(unlockKey)
   131  	test.Assert(t, val == "bb")
   132  
   133  	// unlock key can be reset
   134  	ri.ForceSetTag(unlockKey, "bb")
   135  	val, _ = ri.Tag(unlockKey)
   136  	test.Assert(t, val == "bb")
   137  }
   138  
   139  func TestGetTag(t *testing.T) {
   140  	clusterKey, idcKey, myCluster, myIDC, mock := "cluster", "idc", "myCluster", "myIDC", "mock"
   141  
   142  	ctrl := gomock.NewController(t)
   143  	defer ctrl.Finish()
   144  	inst := mocksdiscovery.NewMockInstance(ctrl)
   145  	inst.EXPECT().Tag(gomock.Any()).DoAndReturn(
   146  		func(key string) (string, bool) {
   147  			switch key {
   148  			case clusterKey:
   149  				return myCluster, true
   150  			case idcKey:
   151  				return myIDC, true
   152  			}
   153  			return "", false
   154  		}).AnyTimes()
   155  
   156  	bi := &rpcinfo.EndpointBasicInfo{
   157  		ServiceName: "service",
   158  	}
   159  	ri := remoteinfo.NewRemoteInfo(bi, "method1")
   160  
   161  	// case1: no cluster and idc
   162  	valCluster, clusterOk := ri.Tag(clusterKey)
   163  	valIDC, idcOk := ri.Tag(idcKey)
   164  	test.Assert(t, !clusterOk)
   165  	test.Assert(t, valCluster == "", valCluster)
   166  	test.Assert(t, !idcOk)
   167  	test.Assert(t, valIDC == "", valIDC)
   168  
   169  	// case2: have cluster and idc which value are from tag set
   170  	ri.SetTag(clusterKey, mock)
   171  	ri.SetTag(idcKey, mock)
   172  	valCluster, clusterOk = ri.Tag(clusterKey)
   173  	valIDC, idcOk = ri.Tag(idcKey)
   174  	test.Assert(t, clusterOk)
   175  	test.Assert(t, valCluster == mock, valCluster)
   176  	test.Assert(t, idcOk)
   177  	test.Assert(t, valIDC == mock, valIDC)
   178  
   179  	// case3: have cluster and idc which value are from instance, the priority of tags from instance is higher than tag set
   180  	ri.SetInstance(inst)
   181  	valCluster, clusterOk = ri.Tag(clusterKey)
   182  	valIDC, idcOk = ri.Tag(idcKey)
   183  	test.Assert(t, clusterOk)
   184  	test.Assert(t, valCluster == myCluster, valCluster)
   185  	test.Assert(t, idcOk)
   186  	test.Assert(t, valIDC == myIDC, valIDC)
   187  }
   188  
   189  func TestRecycleRace(t *testing.T) {
   190  	ri := remoteinfo.NewRemoteInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "service", Tags: map[string]string{"key1": "val1"}}, "method1")
   191  
   192  	// test the data race problem caused by tag modification
   193  	var wg sync.WaitGroup
   194  	wg.Add(2)
   195  	go func() {
   196  		ri.ForceSetTag("key11", "val11")
   197  		wg.Done()
   198  	}()
   199  	go func() {
   200  		ri.(internal.Reusable).Recycle()
   201  		wg.Done()
   202  	}()
   203  	wg.Wait()
   204  }