trpc.group/trpc-go/trpc-go@v1.0.3/client/client_test.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package client_test
    15  
    16  import (
    17  	"context"
    18  	"errors"
    19  	"fmt"
    20  	"net"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/stretchr/testify/require"
    26  	trpcpb "trpc.group/trpc/trpc-protocol/pb/go/trpc"
    27  
    28  	trpc "trpc.group/trpc-go/trpc-go"
    29  	"trpc.group/trpc-go/trpc-go/client"
    30  	"trpc.group/trpc-go/trpc-go/codec"
    31  	"trpc.group/trpc-go/trpc-go/errs"
    32  	"trpc.group/trpc-go/trpc-go/filter"
    33  	"trpc.group/trpc-go/trpc-go/naming/registry"
    34  	"trpc.group/trpc-go/trpc-go/naming/selector"
    35  	"trpc.group/trpc-go/trpc-go/transport"
    36  
    37  	_ "trpc.group/trpc-go/trpc-go"
    38  )
    39  
    40  // go test -v -coverprofile=cover.out
    41  // go tool cover -func=cover.out
    42  
    43  func TestMain(m *testing.M) {
    44  	transport.DefaultClientTransport = &fakeTransport{}
    45  	selector.Register("fake", &fakeSelector{}) // fake://{endpoint}
    46  	transport.RegisterClientTransport("fake", &fakeTransport{})
    47  	m.Run()
    48  }
    49  
    50  func TestClient(t *testing.T) {
    51  	ctx := context.Background()
    52  	codec.RegisterSerializer(0, &codec.NoopSerialization{})
    53  	codec.Register("fake", nil, &fakeCodec{})
    54  
    55  	cli := client.New()
    56  	require.Equal(t, cli, client.DefaultClient)
    57  
    58  	// test if response is valid
    59  	reqBody := &codec.Body{Data: []byte("body")}
    60  	rspBody := &codec.Body{}
    61  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
    62  		client.WithTimeout(time.Second), client.WithProtocol("fake")))
    63  	require.Equal(t, []byte("body"), rspBody.Data)
    64  
    65  	// test setting req/resp head
    66  	reqhead := &registry.Node{}
    67  	rsphead := &registry.Node{}
    68  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
    69  		client.WithReqHead(reqhead), client.WithRspHead(rsphead), client.WithProtocol("fake")))
    70  
    71  	// test client options
    72  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
    73  		client.WithTimeout(time.Second),
    74  		client.WithServiceName("trpc.app.callee.service"),
    75  		client.WithCallerServiceName("trpc.app.caller.service"),
    76  		client.WithSerializationType(codec.SerializationTypeNoop),
    77  		client.WithCompressType(codec.CompressTypeGzip),
    78  		client.WithCurrentSerializationType(codec.SerializationTypeNoop),
    79  		client.WithCurrentCompressType(codec.CompressTypeNoop),
    80  		client.WithMetaData("key", []byte("value")),
    81  		client.WithProtocol("fake")))
    82  
    83  	// test selecting node with network: udp
    84  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("fake://udpnetwork"),
    85  		client.WithTimeout(time.Second), client.WithProtocol("fake")))
    86  
    87  	// test selecting node with network: unknown, which will use tcp by default
    88  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("fake://unknownnetwork"),
    89  		client.WithTimeout(time.Second), client.WithProtocol("fake")))
    90  
    91  	// test setting namespace in msg
    92  	ctx = context.Background()
    93  	ctx, msg := codec.WithNewMessage(ctx)
    94  	msg.WithNamespace("Development") // getServiceInfoOptions will set env info according to the namespace
    95  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
    96  		client.WithTimeout(time.Second), client.WithProtocol("fake")))
    97  	require.Equal(t, []byte("body"), rspBody.Data)
    98  
    99  	// test that env info from upstream service has higher priority
   100  	ctx = context.Background()
   101  	ctx, msg = codec.WithNewMessage(ctx)
   102  	msg.WithEnvTransfer("faketransfer") // env info from upstream service exists
   103  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   104  		client.WithTimeout(time.Second), client.WithProtocol("fake")))
   105  	require.Equal(t, []byte("body"), rspBody.Data)
   106  
   107  	// test disabling service router, which will clear env info from msg
   108  	ctx = context.Background()
   109  	ctx, msg = codec.WithNewMessage(ctx)
   110  	msg.WithEnvTransfer("faketransfer") // env info from upstream service exists
   111  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   112  		client.WithTimeout(time.Second), client.WithProtocol("fake"),
   113  		client.WithDisableServiceRouter())) // opts that disables service router
   114  	require.Equal(t, []byte("body"), rspBody.Data)
   115  	require.Equal(t, msg.EnvTransfer(), "") // env info from upstream service was cleared
   116  
   117  	// test setting CalleeMethod in opts
   118  	// updateMsg will then update CalleeMethod in msg
   119  	ctx = context.Background()
   120  	ctx, msg = codec.WithNewMessage(ctx)
   121  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   122  		client.WithTimeout(time.Second), client.WithProtocol("fake"),
   123  		client.WithCalleeMethod("fakemethod"))) // opts 中指定了 CalleeMethod
   124  	require.Equal(t, msg.CalleeMethod(), "fakemethod") // msg 中的 CalleeMethod 被更新
   125  
   126  	// test that the parameters can be extracted from msg in the prev filter
   127  	ctx = context.Background()
   128  	ctx, msg = codec.WithNewMessage(ctx)
   129  	rid := uint32(100000)
   130  	msg.WithRequestID(uint32(rid))
   131  
   132  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   133  		client.WithTimeout(time.Second), client.WithProtocol("fake"),
   134  		client.WithFilter(func(ctx context.Context, req interface{}, rsp interface{}, f filter.ClientHandleFunc) (err error) {
   135  			msg := trpc.Message(ctx)
   136  			require.Equal(t, rid, msg.RequestID())
   137  			return f(ctx, req, rsp)
   138  		})))
   139  
   140  	// test setting CallType in opts
   141  	// updateMsg will then update CallType in msg
   142  	ctx = context.Background()
   143  	head := &trpcpb.RequestProtocol{}
   144  	ctx, msg = codec.WithNewMessage(ctx)
   145  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   146  		client.WithProtocol("fake"),
   147  		client.WithSendOnly(),
   148  		client.WithReqHead(head),
   149  	))
   150  	require.Equal(t, msg.CallType(), codec.SendOnly)
   151  }
   152  
   153  func TestClientFail(t *testing.T) {
   154  	ctx := context.Background()
   155  	codec.RegisterSerializer(0, &codec.NoopSerialization{})
   156  	codec.Register("fake", nil, &fakeCodec{})
   157  
   158  	cli := client.New()
   159  	require.Equal(t, cli, client.DefaultClient)
   160  
   161  	reqBody := &codec.Body{Data: []byte("body")}
   162  	rspBody := &codec.Body{}
   163  	// test code failure
   164  	require.NotNil(t, cli.Invoke(ctx, reqBody, rspBody,
   165  		client.WithTarget("ip://127.0.0.1:8080"),
   166  		client.WithTimeout(time.Second),
   167  		client.WithSerializationType(codec.SerializationTypeNoop)))
   168  
   169  	// test invalid target
   170  	err := cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip/:/127.0.0.1:8080"),
   171  		client.WithProtocol("fake"))
   172  	require.NotNil(t, err)
   173  	require.Contains(t, err.Error(), "invalid")
   174  
   175  	// test target selector that not exists
   176  	err = cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("cl6://127.0.0.1:8080"),
   177  		client.WithProtocol("fake"))
   178  	require.NotNil(t, err)
   179  	require.Contains(t, err.Error(), "not exist")
   180  
   181  	// test recording selected node
   182  	node := &registry.Node{}
   183  	require.Nil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   184  		client.WithSelectorNode(node), client.WithProtocol("fake")))
   185  	require.Equal(t, node.Address, "127.0.0.1:8080")
   186  	require.Equal(t, node.ServiceName, "127.0.0.1:8080")
   187  	require.Empty(t, node.Network)
   188  
   189  	// test encode failure
   190  	reqBody = &codec.Body{Data: []byte("failbody")}
   191  	require.NotNil(t, cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   192  		client.WithProtocol("fake"), client.WithSerializationType(codec.SerializationTypeNoop)))
   193  
   194  	// test network failure
   195  	reqBody = &codec.Body{Data: []byte("callfail")}
   196  	err = cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   197  		client.WithProtocol("fake"), client.WithSerializationType(codec.SerializationTypeNoop))
   198  	assert.NotNil(t, err)
   199  
   200  	// test response failure
   201  	reqBody = &codec.Body{Data: []byte("businessfail")}
   202  	err = cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   203  		client.WithProtocol("fake"), client.WithSerializationType(codec.SerializationTypeNoop))
   204  
   205  	reqBody = &codec.Body{Data: []byte("msgfail")}
   206  	err = cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   207  		client.WithProtocol("fake"), client.WithSerializationType(codec.SerializationTypeNoop))
   208  	assert.NotNil(t, err)
   209  
   210  	// test nil rsp
   211  	reqBody = &codec.Body{Data: []byte("nilrsp")}
   212  	err = cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   213  		client.WithProtocol("fake"), client.WithSerializationType(codec.SerializationTypeNoop))
   214  	assert.Nil(t, err)
   215  
   216  	// test timeout
   217  	reqBody = &codec.Body{Data: []byte("timeout")}
   218  	err = cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"),
   219  		client.WithProtocol("fake"), client.WithSerializationType(codec.SerializationTypeNoop))
   220  	assert.NotNil(t, err)
   221  
   222  	// test select node failure
   223  	reqBody = &codec.Body{Data: []byte("body")}
   224  	err = cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("fake://selectfail"),
   225  		client.WithTimeout(time.Second), client.WithProtocol("fake"))
   226  	assert.NotNil(t, err)
   227  
   228  	// test selecting the node with empty addr
   229  	err = cli.Invoke(ctx, reqBody, rspBody, client.WithTarget("fake://emptynode"),
   230  		client.WithTimeout(time.Second), client.WithProtocol("fake"))
   231  	assert.NotNil(t, err)
   232  
   233  }
   234  
   235  func TestClientAddrResolve(t *testing.T) {
   236  	ctx := context.Background()
   237  	codec.RegisterSerializer(0, &codec.NoopSerialization{})
   238  	codec.Register("fake", nil, &fakeCodec{})
   239  	cli := client.New()
   240  
   241  	reqBody := &codec.Body{Data: []byte("body")}
   242  	rspBody := &codec.Body{}
   243  	// test target with ip schema
   244  	nctx, _ := codec.WithNewMessage(ctx)
   245  	_ = cli.Invoke(nctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"), client.WithProtocol("fake"))
   246  	assert.Equal(t, "127.0.0.1:8080", codec.Message(nctx).RemoteAddr().String())
   247  
   248  	// test target with ip schema and network: tcp
   249  	nctx, _ = codec.WithNewMessage(ctx)
   250  	_ = cli.Invoke(nctx, reqBody, rspBody,
   251  		client.WithTarget("ip://127.0.0.1:8080"),
   252  		client.WithNetwork("tcp"),
   253  		client.WithProtocol("fake"),
   254  	)
   255  	require.Equal(t, "127.0.0.1:8080", codec.Message(nctx).RemoteAddr().String())
   256  
   257  	// test target with hostname schema
   258  	nctx, _ = codec.WithNewMessage(ctx)
   259  	_ = cli.Invoke(nctx, reqBody, rspBody, client.WithTarget("ip://www.qq.com:8080"), client.WithProtocol("fake"))
   260  	assert.Nil(t, codec.Message(nctx).RemoteAddr())
   261  
   262  	// test calling target with ip schema failure
   263  	nctx, msg := codec.WithNewMessage(ctx)
   264  	reqBody = &codec.Body{Data: []byte("callfail")}
   265  	err := cli.Invoke(nctx, reqBody, rspBody, client.WithTarget("ip://127.0.0.1:8080"), client.WithProtocol("fake"))
   266  	assert.NotNil(t, err)
   267  	assert.Equal(t, "127.0.0.1:8080", msg.RemoteAddr().String())
   268  
   269  	// test target with unix schema
   270  	nctx, _ = codec.WithNewMessage(ctx)
   271  	_ = cli.Invoke(nctx, reqBody, rspBody,
   272  		client.WithTarget("unix://temp.sock"),
   273  		client.WithNetwork("unix"),
   274  		client.WithProtocol("fake"),
   275  	)
   276  	require.Equal(t, "temp.sock", codec.Message(nctx).RemoteAddr().String())
   277  }
   278  
   279  func TestTimeout(t *testing.T) {
   280  	codec.RegisterSerializer(0, &codec.NoopSerialization{})
   281  	codec.Register("fake", nil, &fakeCodec{})
   282  	target, protocol := "ip://127.0.0.1:8080", "fake"
   283  
   284  	cli := client.New()
   285  	rspBody := &codec.Body{}
   286  	err := cli.Invoke(context.Background(),
   287  		&codec.Body{Data: []byte("timeout")}, rspBody,
   288  		client.WithTarget(target),
   289  		client.WithProtocol(protocol))
   290  	require.NotNil(t, err)
   291  	e, ok := err.(*errs.Error)
   292  	require.True(t, ok)
   293  	require.Equal(t, errs.RetClientTimeout, e.Code)
   294  
   295  	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
   296  	defer cancel()
   297  	err = cli.Invoke(ctx,
   298  		&codec.Body{Data: []byte("timeout")}, rspBody,
   299  		client.WithTarget(target),
   300  		client.WithProtocol(protocol))
   301  	require.NotNil(t, err)
   302  	e, ok = err.(*errs.Error)
   303  	require.True(t, ok)
   304  	require.Equal(t, errs.RetClientFullLinkTimeout, e.Code)
   305  }
   306  
   307  func TestSameCalleeMultiServiceName(t *testing.T) {
   308  	callee := "trpc.test.pbcallee"
   309  	serviceNames := []string{
   310  		"trpc.test.helloworld0",
   311  		"trpc.test.helloworld1",
   312  		"trpc.test.helloworld2",
   313  		"trpc.test.helloworld3",
   314  	}
   315  	for i := range serviceNames {
   316  		if i != 2 {
   317  			require.Nil(t, client.RegisterClientConfig(callee, &client.BackendConfig{
   318  				ServiceName: serviceNames[i],
   319  				Compression: codec.CompressTypeSnappy,
   320  			}))
   321  			continue
   322  		}
   323  		require.Nil(t, client.RegisterClientConfig(callee, &client.BackendConfig{
   324  			ServiceName: serviceNames[i],
   325  			Compression: codec.CompressTypeBlockSnappy,
   326  		}))
   327  	}
   328  	ctx, msg := codec.EnsureMessage(context.Background())
   329  	msg.WithCalleeServiceName(callee)
   330  	require.NotNil(t, client.DefaultClient.Invoke(ctx, nil, nil, client.WithServiceName(serviceNames[0])))
   331  	require.Equal(t, codec.CompressTypeSnappy, msg.CompressType())
   332  	ctx, msg = codec.EnsureMessage(context.Background())
   333  	msg.WithCalleeServiceName(callee)
   334  	require.NotNil(t, client.DefaultClient.Invoke(ctx, nil, nil, client.WithServiceName(serviceNames[2])))
   335  	require.Equal(t, codec.CompressTypeBlockSnappy, msg.CompressType())
   336  }
   337  
   338  func TestMultiplexedUseLatestMsg(t *testing.T) {
   339  	codec.RegisterSerializer(0, &codec.NoopSerialization{})
   340  	const target = "ip://127.0.0.1:8080"
   341  
   342  	rspBody := &codec.Body{}
   343  	require.Nil(t, client.New().Invoke(context.Background(),
   344  		&codec.Body{Data: []byte(t.Name())}, rspBody,
   345  		client.WithTarget(target),
   346  		client.WithTransport(&multiplexedTransport{
   347  			require: func(_ context.Context, _ []byte, opts ...transport.RoundTripOption) {
   348  				var o transport.RoundTripOptions
   349  				for _, opt := range opts {
   350  					opt(&o)
   351  				}
   352  				require.NotZero(t, o.Msg.RequestID())
   353  			}}),
   354  		client.WithMultiplexed(true),
   355  		client.WithFilter(func(ctx context.Context, req, rsp interface{}, next filter.ClientHandleFunc) error {
   356  			// make a copy of the msg, after next, copy the new msg back.
   357  			oldMsg := codec.Message(ctx)
   358  			ctx, msg := codec.WithNewMessage(ctx)
   359  			codec.CopyMsg(msg, oldMsg)
   360  			err := next(ctx, req, rsp)
   361  			codec.CopyMsg(oldMsg, msg)
   362  			return err
   363  		}),
   364  	))
   365  }
   366  
   367  func TestFixTimeout(t *testing.T) {
   368  	codec.RegisterSerializer(0, &codec.NoopSerialization{})
   369  	codec.Register("fake", nil, &fakeCodec{})
   370  	target, protocol := "ip://127.0.0.1:8080", "fake"
   371  
   372  	cli := client.New()
   373  
   374  	rspBody := &codec.Body{}
   375  	t.Run("RetClientCanceled", func(t *testing.T) {
   376  		ctx, cancel := context.WithCancel(context.Background())
   377  		cancel()
   378  		err := cli.Invoke(ctx,
   379  			&codec.Body{Data: []byte("clientCanceled")}, rspBody,
   380  			client.WithTarget(target),
   381  			client.WithProtocol(protocol))
   382  		require.Equal(t, errs.RetClientCanceled, errs.Code(err))
   383  	})
   384  
   385  	t.Run("RetClientFullLinkTimeout", func(t *testing.T) {
   386  		ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(1*time.Millisecond))
   387  		defer cancel()
   388  		var d time.Duration
   389  		deadline, ok := t.Deadline()
   390  		if !ok {
   391  			d = 5 * time.Second
   392  		} else {
   393  			const arbitraryCleanupMargin = 1 * time.Second
   394  			d = time.Until(deadline) - arbitraryCleanupMargin
   395  		}
   396  		timer := time.NewTimer(d)
   397  		defer timer.Stop()
   398  		select {
   399  		case <-timer.C:
   400  			t.Fatalf(" context not timed out after %v", d)
   401  		case <-ctx.Done():
   402  		}
   403  		if e := ctx.Err(); e != context.DeadlineExceeded {
   404  			t.Errorf("c.Err() == %v; want %v", e, context.DeadlineExceeded)
   405  		}
   406  		err := cli.Invoke(ctx,
   407  			&codec.Body{Data: []byte("fixTimeout")}, rspBody,
   408  			client.WithTarget(target),
   409  			client.WithProtocol(protocol))
   410  		require.Equal(t, errs.RetClientFullLinkTimeout, errs.Code(err))
   411  	})
   412  }
   413  
   414  func TestSelectorRemoteAddrUseUserProvidedParser(t *testing.T) {
   415  	selector.Register(t.Name(), &fSelector{
   416  		selectNode: func(s string, option ...selector.Option) (*registry.Node, error) {
   417  			return &registry.Node{
   418  				Network: t.Name(),
   419  				Address: t.Name(),
   420  				ParseAddr: func(network, address string) net.Addr {
   421  					return newUnresolvedAddr(network, address)
   422  				}}, nil
   423  		},
   424  		report: func(node *registry.Node, duration time.Duration, err error) error { return nil },
   425  	})
   426  	fake := "fake"
   427  	codec.Register(fake, nil, &fakeCodec{})
   428  	ctx := trpc.BackgroundContext()
   429  	require.NotNil(t, client.New().Invoke(ctx, "failbody", nil,
   430  		client.WithServiceName(t.Name()),
   431  		client.WithProtocol(fake),
   432  		client.WithTarget(fmt.Sprintf("%s://xxx", t.Name()))))
   433  	addr := trpc.Message(ctx).RemoteAddr()
   434  	require.NotNil(t, addr)
   435  	require.Equal(t, t.Name(), addr.Network())
   436  	require.Equal(t, t.Name(), addr.String())
   437  }
   438  
   439  type multiplexedTransport struct {
   440  	require func(context.Context, []byte, ...transport.RoundTripOption)
   441  	fakeTransport
   442  }
   443  
   444  func (t *multiplexedTransport) RoundTrip(
   445  	ctx context.Context,
   446  	req []byte,
   447  	opts ...transport.RoundTripOption,
   448  ) ([]byte, error) {
   449  	t.require(ctx, req, opts...)
   450  	return t.fakeTransport.RoundTrip(ctx, req, opts...)
   451  }
   452  
   453  type fakeTransport struct {
   454  	send  func() error
   455  	recv  func() ([]byte, error)
   456  	close func()
   457  }
   458  
   459  func (c *fakeTransport) RoundTrip(ctx context.Context, req []byte,
   460  	roundTripOpts ...transport.RoundTripOption) (rsp []byte, err error) {
   461  	time.Sleep(time.Millisecond * 2)
   462  	if string(req) == "callfail" {
   463  		return nil, errors.New("transport call fail")
   464  	}
   465  
   466  	if string(req) == "timeout" {
   467  		return nil, &errs.Error{
   468  			Type: errs.ErrorTypeFramework,
   469  			Code: errs.RetClientTimeout,
   470  			Msg:  "transport call fail",
   471  		}
   472  	}
   473  
   474  	if string(req) == "nilrsp" {
   475  		return nil, nil
   476  	}
   477  	return req, nil
   478  }
   479  
   480  func (c *fakeTransport) Send(ctx context.Context, req []byte, opts ...transport.RoundTripOption) error {
   481  	if c.send != nil {
   482  		return c.send()
   483  	}
   484  	return nil
   485  }
   486  
   487  func (c *fakeTransport) Recv(ctx context.Context, opts ...transport.RoundTripOption) ([]byte, error) {
   488  	if c.recv != nil {
   489  		return c.recv()
   490  	}
   491  	return []byte("body"), nil
   492  }
   493  
   494  func (c *fakeTransport) Init(ctx context.Context, opts ...transport.RoundTripOption) error {
   495  	return nil
   496  }
   497  func (c *fakeTransport) Close(ctx context.Context) {
   498  	if c.close != nil {
   499  		c.close()
   500  	}
   501  }
   502  
   503  type fakeCodec struct {
   504  }
   505  
   506  func (c *fakeCodec) Encode(msg codec.Msg, reqBody []byte) (reqBuf []byte, err error) {
   507  	if string(reqBody) == "failbody" {
   508  		return nil, errors.New("encode fail")
   509  	}
   510  	return reqBody, nil
   511  }
   512  
   513  func (c *fakeCodec) Decode(msg codec.Msg, rspBuf []byte) (rspBody []byte, err error) {
   514  	if string(rspBuf) == "businessfail" {
   515  		return nil, errors.New("businessfail")
   516  	}
   517  
   518  	if string(rspBuf) == "msgfail" {
   519  		msg.WithClientRspErr(errors.New("msgfail"))
   520  		return nil, nil
   521  	}
   522  	return rspBuf, nil
   523  }
   524  
   525  type fakeSelector struct {
   526  }
   527  
   528  func (c *fakeSelector) Select(serviceName string, opt ...selector.Option) (*registry.Node, error) {
   529  	if serviceName == "selectfail" {
   530  		return nil, errors.New("selectfail")
   531  	}
   532  
   533  	if serviceName == "emptynode" {
   534  		return &registry.Node{}, nil
   535  	}
   536  
   537  	if serviceName == "udpnetwork" {
   538  		return &registry.Node{
   539  			Network: "udp",
   540  			Address: "127.0.0.1:8080",
   541  		}, nil
   542  	}
   543  
   544  	if serviceName == "unknownnetwork" {
   545  		return &registry.Node{
   546  			Network: "unknown",
   547  			Address: "127.0.0.1:8080",
   548  		}, nil
   549  	}
   550  
   551  	return nil, errors.New("unknown servicename")
   552  }
   553  
   554  func (c *fakeSelector) Report(node *registry.Node, cost time.Duration, err error) error {
   555  	return nil
   556  }
   557  
   558  type fSelector struct {
   559  	selectNode func(string, ...selector.Option) (*registry.Node, error)
   560  	report     func(*registry.Node, time.Duration, error) error
   561  }
   562  
   563  func (s *fSelector) Select(serviceName string, opts ...selector.Option) (*registry.Node, error) {
   564  	return s.selectNode(serviceName, opts...)
   565  }
   566  
   567  func (s *fSelector) Report(node *registry.Node, cost time.Duration, err error) error {
   568  	return s.report(node, cost, err)
   569  }
   570  
   571  // newUnresolvedAddr returns a new unresolvedAddr.
   572  func newUnresolvedAddr(network, address string) *unresolvedAddr {
   573  	return &unresolvedAddr{network: network, address: address}
   574  }
   575  
   576  var _ net.Addr = (*unresolvedAddr)(nil)
   577  
   578  // unresolvedAddr is a net.Addr which returns the original network or address.
   579  type unresolvedAddr struct {
   580  	network string
   581  	address string
   582  }
   583  
   584  // Network returns the unresolved original network.
   585  func (a *unresolvedAddr) Network() string {
   586  	return a.network
   587  }
   588  
   589  // String returns the unresolved original address.
   590  func (a *unresolvedAddr) String() string {
   591  	return a.address
   592  }