From 91714bcd34dd30892b1124af5d3f9fd5434e9077 Mon Sep 17 00:00:00 2001 From: longxboy Date: Fri, 22 Oct 2021 15:57:01 +0800 Subject: [PATCH] test: add transport grpc test (#1580) * add transport grpc test * fix node --- internal/testdata/helloworld/helloworld.pb.go | 221 ++++++++++++++++++ internal/testdata/helloworld/helloworld.proto | 27 +++ .../testdata/helloworld/helloworld_grpc.pb.go | 103 ++++++++ .../testdata/helloworld/helloworld_http.pb.go | 74 ++++++ selector/p2c/p2c_test.go | 12 +- transport/grpc/balancer_test.go | 29 +++ transport/grpc/server_test.go | 71 +++++- 7 files changed, 526 insertions(+), 11 deletions(-) create mode 100644 internal/testdata/helloworld/helloworld.pb.go create mode 100644 internal/testdata/helloworld/helloworld.proto create mode 100644 internal/testdata/helloworld/helloworld_grpc.pb.go create mode 100644 internal/testdata/helloworld/helloworld_http.pb.go create mode 100644 transport/grpc/balancer_test.go diff --git a/internal/testdata/helloworld/helloworld.pb.go b/internal/testdata/helloworld/helloworld.pb.go new file mode 100644 index 000000000..656819d43 --- /dev/null +++ b/internal/testdata/helloworld/helloworld.pb.go @@ -0,0 +1,221 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.17.3 +// source: helloworld/helloworld.proto + +package helloworld + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// The request message containing the user's name. +type HelloRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *HelloRequest) Reset() { + *x = HelloRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_helloworld_helloworld_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HelloRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloRequest) ProtoMessage() {} + +func (x *HelloRequest) ProtoReflect() protoreflect.Message { + mi := &file_helloworld_helloworld_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. +func (*HelloRequest) Descriptor() ([]byte, []int) { + return file_helloworld_helloworld_proto_rawDescGZIP(), []int{0} +} + +func (x *HelloRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// The response message containing the greetings +type HelloReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *HelloReply) Reset() { + *x = HelloReply{} + if protoimpl.UnsafeEnabled { + mi := &file_helloworld_helloworld_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HelloReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloReply) ProtoMessage() {} + +func (x *HelloReply) ProtoReflect() protoreflect.Message { + mi := &file_helloworld_helloworld_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead. +func (*HelloReply) Descriptor() ([]byte, []int) { + return file_helloworld_helloworld_proto_rawDescGZIP(), []int{1} +} + +func (x *HelloReply) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_helloworld_helloworld_proto protoreflect.FileDescriptor + +var file_helloworld_helloworld_proto_rawDesc = []byte{ + 0x0a, 0x1b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2f, 0x68, 0x65, 0x6c, + 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x68, + 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x26, 0x0a, 0x0a, 0x48, + 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x32, 0x63, 0x0a, 0x07, 0x47, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x12, 0x58, + 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x18, 0x2e, 0x68, 0x65, 0x6c, + 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, + 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1a, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, + 0x64, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, + 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x68, 0x65, 0x6c, + 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_helloworld_helloworld_proto_rawDescOnce sync.Once + file_helloworld_helloworld_proto_rawDescData = file_helloworld_helloworld_proto_rawDesc +) + +func file_helloworld_helloworld_proto_rawDescGZIP() []byte { + file_helloworld_helloworld_proto_rawDescOnce.Do(func() { + file_helloworld_helloworld_proto_rawDescData = protoimpl.X.CompressGZIP(file_helloworld_helloworld_proto_rawDescData) + }) + return file_helloworld_helloworld_proto_rawDescData +} + +var file_helloworld_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_helloworld_helloworld_proto_goTypes = []interface{}{ + (*HelloRequest)(nil), // 0: helloworld.HelloRequest + (*HelloReply)(nil), // 1: helloworld.HelloReply +} +var file_helloworld_helloworld_proto_depIdxs = []int32{ + 0, // 0: helloworld.Greeter.SayHello:input_type -> helloworld.HelloRequest + 1, // 1: helloworld.Greeter.SayHello:output_type -> helloworld.HelloReply + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_helloworld_helloworld_proto_init() } +func file_helloworld_helloworld_proto_init() { + if File_helloworld_helloworld_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_helloworld_helloworld_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HelloRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_helloworld_helloworld_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HelloReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helloworld_helloworld_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helloworld_helloworld_proto_goTypes, + DependencyIndexes: file_helloworld_helloworld_proto_depIdxs, + MessageInfos: file_helloworld_helloworld_proto_msgTypes, + }.Build() + File_helloworld_helloworld_proto = out.File + file_helloworld_helloworld_proto_rawDesc = nil + file_helloworld_helloworld_proto_goTypes = nil + file_helloworld_helloworld_proto_depIdxs = nil +} diff --git a/internal/testdata/helloworld/helloworld.proto b/internal/testdata/helloworld/helloworld.proto new file mode 100644 index 000000000..bdac62c1f --- /dev/null +++ b/internal/testdata/helloworld/helloworld.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package helloworld; + +import "google/api/annotations.proto"; + +option go_package = "github.com/go-kratos/kratos/v2/internal/testdata/helloworld"; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) { + option (google.api.http) = { + get: "/helloworld/{name}", + }; + } +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/internal/testdata/helloworld/helloworld_grpc.pb.go b/internal/testdata/helloworld/helloworld_grpc.pb.go new file mode 100644 index 000000000..4e1c32b3d --- /dev/null +++ b/internal/testdata/helloworld/helloworld_grpc.pb.go @@ -0,0 +1,103 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package helloworld + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// GreeterClient is the client API for Greeter service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type GreeterClient interface { + // Sends a greeting + SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) +} + +type greeterClient struct { + cc grpc.ClientConnInterface +} + +func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient { + return &greeterClient{cc} +} + +func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { + out := new(HelloReply) + err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GreeterServer is the server API for Greeter service. +// All implementations must embed UnimplementedGreeterServer +// for forward compatibility +type GreeterServer interface { + // Sends a greeting + SayHello(context.Context, *HelloRequest) (*HelloReply, error) + mustEmbedUnimplementedGreeterServer() +} + +// UnimplementedGreeterServer must be embedded to have forward compatible implementations. +type UnimplementedGreeterServer struct { +} + +func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") +} +func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {} + +// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to GreeterServer will +// result in compilation errors. +type UnsafeGreeterServer interface { + mustEmbedUnimplementedGreeterServer() +} + +func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) { + s.RegisterService(&Greeter_ServiceDesc, srv) +} + +func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GreeterServer).SayHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/helloworld.Greeter/SayHello", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Greeter_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helloworld.Greeter", + HandlerType: (*GreeterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SayHello", + Handler: _Greeter_SayHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helloworld/helloworld.proto", +} diff --git a/internal/testdata/helloworld/helloworld_http.pb.go b/internal/testdata/helloworld/helloworld_http.pb.go new file mode 100644 index 000000000..368b57186 --- /dev/null +++ b/internal/testdata/helloworld/helloworld_http.pb.go @@ -0,0 +1,74 @@ +// Code generated by protoc-gen-go-http. DO NOT EDIT. +// versions: +// protoc-gen-go-http v2.1.0 + +package helloworld + +import ( + context "context" + http "github.com/go-kratos/kratos/v2/transport/http" + binding "github.com/go-kratos/kratos/v2/transport/http/binding" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the kratos package it is being compiled against. +var _ = new(context.Context) +var _ = binding.EncodeURL + +const _ = http.SupportPackageIsVersion1 + +type GreeterHTTPServer interface { + SayHello(context.Context, *HelloRequest) (*HelloReply, error) +} + +func RegisterGreeterHTTPServer(s *http.Server, srv GreeterHTTPServer) { + r := s.Route("/") + r.GET("/helloworld/{name}", _Greeter_SayHello0_HTTP_Handler(srv)) +} + +func _Greeter_SayHello0_HTTP_Handler(srv GreeterHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in HelloRequest + if err := ctx.BindQuery(&in); err != nil { + return err + } + if err := ctx.BindVars(&in); err != nil { + return err + } + http.SetOperation(ctx, "/helloworld.Greeter/SayHello") + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.SayHello(ctx, req.(*HelloRequest)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*HelloReply) + return ctx.Result(200, reply) + } +} + +type GreeterHTTPClient interface { + SayHello(ctx context.Context, req *HelloRequest, opts ...http.CallOption) (rsp *HelloReply, err error) +} + +type GreeterHTTPClientImpl struct { + cc *http.Client +} + +func NewGreeterHTTPClient(client *http.Client) GreeterHTTPClient { + return &GreeterHTTPClientImpl{client} +} + +func (c *GreeterHTTPClientImpl) SayHello(ctx context.Context, in *HelloRequest, opts ...http.CallOption) (*HelloReply, error) { + var out HelloReply + pattern := "/helloworld/{name}" + path := binding.EncodeURL(pattern, in, true) + opts = append(opts, http.Operation("/helloworld.Greeter/SayHello")) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) + if err != nil { + return nil, err + } + return &out, err +} diff --git a/selector/p2c/p2c_test.go b/selector/p2c/p2c_test.go index aac4495bb..747345a17 100644 --- a/selector/p2c/p2c_test.go +++ b/selector/p2c/p2c_test.go @@ -56,12 +56,12 @@ func TestWrr3(t *testing.T) { }() } group.Wait() - assert.Greater(t, count1, int64(2500)) - assert.Less(t, count1, int64(3500)) - assert.Greater(t, count2, int64(2500)) - assert.Less(t, count2, int64(3500)) - assert.Greater(t, count3, int64(2500)) - assert.Less(t, count3, int64(3500)) + assert.Greater(t, count1, int64(2000)) + assert.Less(t, count1, int64(4000)) + assert.Greater(t, count2, int64(2000)) + assert.Less(t, count2, int64(4000)) + assert.Greater(t, count3, int64(2000)) + assert.Less(t, count3, int64(4000)) } func TestEmpty(t *testing.T) { diff --git a/transport/grpc/balancer_test.go b/transport/grpc/balancer_test.go new file mode 100644 index 000000000..dcce7ffe0 --- /dev/null +++ b/transport/grpc/balancer_test.go @@ -0,0 +1,29 @@ +package grpc + +import ( + "testing" + + "github.com/go-kratos/kratos/v2/selector/filter" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/metadata" +) + +func TestTrailer(t *testing.T) { + trailer := Trailer(metadata.New(map[string]string{"a": "b"})) + assert.Equal(t, "b", trailer.Get("a")) + assert.Equal(t, "", trailer.Get("3")) +} + +func TestBalancerName(t *testing.T) { + o := &clientOptions{} + + WithBalancerName("p2c")(o) + assert.Equal(t, "p2c", o.balancerName) +} + +func TestFilters(t *testing.T) { + o := &clientOptions{} + + WithSelectFilter(filter.Version("2"))(o) + assert.Equal(t, 1, len(o.filters)) +} diff --git a/transport/grpc/server_test.go b/transport/grpc/server_test.go index 3b9f1ede1..87c3483cc 100644 --- a/transport/grpc/server_test.go +++ b/transport/grpc/server_test.go @@ -3,26 +3,62 @@ package grpc import ( "context" "crypto/tls" + "fmt" "net/url" "strings" "testing" "time" + "github.com/go-kratos/kratos/v2/errors" + pb "github.com/go-kratos/kratos/v2/internal/testdata/helloworld" "github.com/go-kratos/kratos/v2/log" "github.com/go-kratos/kratos/v2/middleware" - "google.golang.org/grpc" + "github.com/go-kratos/kratos/v2/transport" "github.com/stretchr/testify/assert" + "google.golang.org/grpc" ) +// server is used to implement helloworld.GreeterServer. +type server struct { + pb.UnimplementedGreeterServer +} + +// SayHello implements helloworld.GreeterServer +func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { + if in.Name == "error" { + return nil, errors.BadRequest("custom_error", fmt.Sprintf("invalid argument %s", in.Name)) + } + if in.Name == "panic" { + panic("server panic") + } + return &pb.HelloReply{Message: fmt.Sprintf("Hello %+v", in.Name)}, nil +} + type testKey struct{} func TestServer(t *testing.T) { ctx := context.Background() ctx = context.WithValue(ctx, testKey{}, "test") - srv := NewServer(Middleware([]middleware.Middleware{ - func(middleware.Handler) middleware.Handler { return nil }, - }...)) + srv := NewServer( + Middleware( + func(handler middleware.Handler) middleware.Handler { + return func(ctx context.Context, req interface{}) (reply interface{}, err error) { + if tr, ok := transport.FromServerContext(ctx); ok { + if tr.ReplyHeader() != nil { + tr.ReplyHeader().Set("req_id", "3344") + } + } + return handler(ctx, req) + } + }), + UnaryInterceptor(func(ctx context.Context, req interface{}, + info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + return handler(ctx, req) + }), + Options(grpc.InitialConnWindowSize(0)), + ) + pb.RegisterGreeterServer(srv, &server{}) if e, err := srv.Endpoint(); err != nil || e == nil || strings.HasSuffix(e.Host, ":0") { t.Fatal(e, err) @@ -45,10 +81,31 @@ func testClient(t *testing.T, srv *Server) { t.Fatal(err) } // new a gRPC client - conn, err := DialInsecure(context.Background(), WithEndpoint(u.Host)) + conn, err := DialInsecure(context.Background(), + WithEndpoint(u.Host), + WithOptions(grpc.WithBlock()), + WithUnaryInterceptor(func(ctx context.Context, method string, req, reply interface{}, + cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + return invoker(ctx, method, req, reply, cc, opts...) + }), + WithMiddleware(func(handler middleware.Handler) middleware.Handler { + return func(ctx context.Context, req interface{}) (reply interface{}, err error) { + if tr, ok := transport.FromClientContext(ctx); ok { + header := tr.RequestHeader() + header.Set("x-md-trace", "2233") + } + return handler(ctx, req) + } + }), + ) if err != nil { t.Fatal(err) } + client := pb.NewGreeterClient(conn) + reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "kratos"}) + fmt.Println(err) + assert.Nil(t, err) + assert.Equal(t, "Hello kratos", reply.Message) _ = conn.Close() } @@ -64,6 +121,10 @@ func TestAddress(t *testing.T) { v := "abc" Address(v)(o) assert.Equal(t, v, o.address) + + u, err := o.Endpoint() + assert.NotNil(t, err) + assert.Nil(t, u) } func TestTimeout(t *testing.T) {