This commit is contained in:
Cyrille Hemidy 2018-03-05 13:36:27 +00:00 committed by GitHub
commit 3448f8b800
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 56 deletions

View File

@ -6,8 +6,9 @@ matrix:
- go: 1.7 - go: 1.7
- go: 1.8 - go: 1.8
- go: 1.9 - go: 1.9
- go: "1.10"
- go: tip - go: tip
script: script:
# TODO: change to "make" when golint, errcheck, staticcheck pass # TODO: change to "make" when golint, errcheck, staticcheck pass
- make deps checkgofmt vet unused test - make deps checkgofmt golint vet unused test

View File

@ -40,7 +40,7 @@ vet:
.PHONY: .PHONY:
errcheck: errcheck:
@go get github.com/kisielk/errcheck @go get github.com/kisielk/errcheck
errcheck $(PKGS) errcheck -verbose $(PKGS)
.PHONY: staticcheck .PHONY: staticcheck
staticcheck: staticcheck:

View File

@ -245,7 +245,9 @@ func main() {
refClient = nil refClient = nil
} }
if cc != nil { if cc != nil {
cc.Close() if err := cc.Close(); err != nil {
fail(err, "Failed to close grpc Client")
}
cc = nil cc = nil
} }
} }
@ -344,7 +346,7 @@ func main() {
} }
h := &handler{dec: dec, descSource: descSource} h := &handler{dec: dec, descSource: descSource}
err := grpcurl.InvokeRpc(ctx, descSource, cc, symbol, addlHeaders, h, h.getRequestData) err := grpcurl.InvokeRPC(ctx, descSource, cc, symbol, addlHeaders, h, h.getRequestData)
if err != nil { if err != nil {
fail(err, "Error invoking method %q", symbol) fail(err, "Error invoking method %q", symbol)
} }
@ -435,10 +437,9 @@ func (h *handler) getRequestData() ([]byte, error) {
var msg json.RawMessage var msg json.RawMessage
if err := h.dec.Decode(&msg); err != nil { if err := h.dec.Decode(&msg); err != nil {
return nil, err return nil, err
} else {
h.reqCount++
return msg, nil
} }
h.reqCount++
return msg, nil
} }
func (*handler) OnReceiveHeaders(md metadata.MD) { func (*handler) OnReceiveHeaders(md metadata.MD) {

View File

@ -225,16 +225,16 @@ func ListMethods(source DescriptorSource, serviceName string) ([]string, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if sd, ok := dsc.(*desc.ServiceDescriptor); !ok { sd, ok := dsc.(*desc.ServiceDescriptor)
if !ok {
return nil, notFound("Service", serviceName) return nil, notFound("Service", serviceName)
} else {
methods := make([]string, 0, len(sd.GetMethods()))
for _, method := range sd.GetMethods() {
methods = append(methods, method.GetName())
}
sort.Strings(methods)
return methods, nil
} }
methods := make([]string, 0, len(sd.GetMethods()))
for _, method := range sd.GetMethods() {
methods = append(methods, method.GetName())
}
sort.Strings(methods)
return methods, nil
} }
type notFoundError string type notFoundError string
@ -276,7 +276,7 @@ type InvocationEventHandler interface {
// the supplier has no more messages, it should return nil, io.EOF. // the supplier has no more messages, it should return nil, io.EOF.
type RequestMessageSupplier func() ([]byte, error) type RequestMessageSupplier func() ([]byte, error)
// InvokeRpc uses te given GRPC connection to invoke the given method. The given descriptor source // InvokeRPC uses te given GRPC connection to invoke the given method. The given descriptor source
// is used to determine the type of method and the type of request and response message. The given // is used to determine the type of method and the type of request and response message. The given
// headers are sent as request metadata. Methods on the given event handler are called as the // headers are sent as request metadata. Methods on the given event handler are called as the
// invocation proceeds. // invocation proceeds.
@ -291,7 +291,7 @@ type RequestMessageSupplier func() ([]byte, error)
// be thread-safe. This is because the requestData function may be called from a different goroutine // be thread-safe. This is because the requestData function may be called from a different goroutine
// than the one invoking event callbacks. (This only happens for bi-directional streaming RPCs, where // than the one invoking event callbacks. (This only happens for bi-directional streaming RPCs, where
// one goroutine sends request messages and another consumes the response messages). // one goroutine sends request messages and another consumes the response messages).
func InvokeRpc(ctx context.Context, source DescriptorSource, cc *grpc.ClientConn, methodName string, func InvokeRPC(ctx context.Context, source DescriptorSource, cc *grpc.ClientConn, methodName string,
headers []string, handler InvocationEventHandler, requestData RequestMessageSupplier) error { headers []string, handler InvocationEventHandler, requestData RequestMessageSupplier) error {
md := MetadataFromHeaders(headers) md := MetadataFromHeaders(headers)
@ -304,9 +304,8 @@ func InvokeRpc(ctx context.Context, source DescriptorSource, cc *grpc.ClientConn
if err != nil { if err != nil {
if isNotFoundError(err) { if isNotFoundError(err) {
return fmt.Errorf("target server does not expose service %q", svc) return fmt.Errorf("target server does not expose service %q", svc)
} else {
return fmt.Errorf("failed to query for service descriptor %q: %v", svc, err)
} }
return fmt.Errorf("failed to query for service descriptor %q: %v", svc, err)
} }
sd, ok := dsc.(*desc.ServiceDescriptor) sd, ok := dsc.(*desc.ServiceDescriptor)
if !ok { if !ok {
@ -345,9 +344,8 @@ func InvokeRpc(ctx context.Context, source DescriptorSource, cc *grpc.ClientConn
return invokeClientStream(ctx, stub, mtd, handler, requestData, req) return invokeClientStream(ctx, stub, mtd, handler, requestData, req)
} else if mtd.IsServerStreaming() { } else if mtd.IsServerStreaming() {
return invokeServerStream(ctx, stub, mtd, handler, requestData, req) return invokeServerStream(ctx, stub, mtd, handler, requestData, req)
} else {
return invokeUnary(ctx, stub, mtd, handler, requestData, req)
} }
return invokeUnary(ctx, stub, mtd, handler, requestData, req)
} }
func invokeUnary(ctx context.Context, stub grpcdynamic.Stub, md *desc.MethodDescriptor, handler InvocationEventHandler, func invokeUnary(ctx context.Context, stub grpcdynamic.Stub, md *desc.MethodDescriptor, handler InvocationEventHandler,
@ -765,9 +763,8 @@ func fullyConvertToDynamic(msgFact *dynamic.MessageFactory, msg proto.Message) (
newVal, err := fullyConvertToDynamic(msgFact, v.(proto.Message)) newVal, err := fullyConvertToDynamic(msgFact, v.(proto.Message))
if err != nil { if err != nil {
return nil, err return nil, err
} else {
dm.PutMapField(fd, k, newVal)
} }
dm.PutMapField(fd, k, newVal)
} }
} }
} else if fd.IsRepeated() { } else if fd.IsRepeated() {
@ -777,9 +774,8 @@ func fullyConvertToDynamic(msgFact *dynamic.MessageFactory, msg proto.Message) (
newVal, err := fullyConvertToDynamic(msgFact, e.(proto.Message)) newVal, err := fullyConvertToDynamic(msgFact, e.(proto.Message))
if err != nil { if err != nil {
return nil, err return nil, err
} else {
dm.SetRepeatedField(fd, i, newVal)
} }
dm.SetRepeatedField(fd, i, newVal)
} }
} }
} else { } else {
@ -788,9 +784,8 @@ func fullyConvertToDynamic(msgFact *dynamic.MessageFactory, msg proto.Message) (
newVal, err := fullyConvertToDynamic(msgFact, v.(proto.Message)) newVal, err := fullyConvertToDynamic(msgFact, v.(proto.Message))
if err != nil { if err != nil {
return nil, err return nil, err
} else {
dm.SetField(fd, newVal)
} }
dm.SetField(fd, newVal)
} }
} }
} }
@ -936,9 +931,8 @@ func BlockingDial(ctx context.Context, address string, creds credentials.Transpo
case res := <-result: case res := <-result:
if conn, ok := res.(*grpc.ClientConn); ok { if conn, ok := res.(*grpc.ClientConn); ok {
return conn, nil return conn, nil
} else {
return nil, res.(error)
} }
return nil, res.(error)
case <-ctx.Done(): case <-ctx.Done():
return nil, ctx.Err() return nil, ctx.Err()
} }

View File

@ -108,7 +108,7 @@ func TestServerDoesNotSupportReflection(t *testing.T) {
t.Errorf("ListMethods should have returned ErrReflectionNotSupported; instead got %v", err) t.Errorf("ListMethods should have returned ErrReflectionNotSupported; instead got %v", err)
} }
err = InvokeRpc(context.Background(), refSource, ccProtoset, "FooService/Method", nil, nil, nil) err = InvokeRPC(context.Background(), refSource, ccProtoset, "FooService/Method", nil, nil, nil)
// InvokeRpc wraps the error, so we just verify the returned error includes the right message // InvokeRpc wraps the error, so we just verify the returned error includes the right message
if err == nil || !strings.Contains(err.Error(), ErrReflectionNotSupported.Error()) { if err == nil || !strings.Contains(err.Error(), ErrReflectionNotSupported.Error()) {
t.Errorf("InvokeRpc should have returned ErrReflectionNotSupported; instead got %v", err) t.Errorf("InvokeRpc should have returned ErrReflectionNotSupported; instead got %v", err)
@ -307,7 +307,7 @@ func TestUnaryReflect(t *testing.T) {
func doTestUnary(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) { func doTestUnary(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) {
// Success // Success
h := &handler{reqMessages: []string{payload1}} h := &handler{reqMessages: []string{payload1}}
err := InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/UnaryCall", makeHeaders(codes.OK), h, h.getRequestData) err := InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/UnaryCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -320,7 +320,7 @@ func doTestUnary(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) {
// Failure // Failure
h = &handler{reqMessages: []string{payload1}} h = &handler{reqMessages: []string{payload1}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/UnaryCall", makeHeaders(codes.NotFound), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/UnaryCall", makeHeaders(codes.NotFound), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -339,7 +339,7 @@ func TestClientStreamReflect(t *testing.T) {
func doTestClientStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) { func doTestClientStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) {
// Success // Success
h := &handler{reqMessages: []string{payload1, payload2, payload3}} h := &handler{reqMessages: []string{payload1, payload2, payload3}}
err := InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingInputCall", makeHeaders(codes.OK), h, h.getRequestData) err := InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/StreamingInputCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -356,7 +356,7 @@ func doTestClientStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSour
// Fail fast (server rejects as soon as possible) // Fail fast (server rejects as soon as possible)
h = &handler{reqMessages: []string{payload1, payload2, payload3}} h = &handler{reqMessages: []string{payload1, payload2, payload3}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingInputCall", makeHeaders(codes.InvalidArgument), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/StreamingInputCall", makeHeaders(codes.InvalidArgument), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -365,7 +365,7 @@ func doTestClientStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSour
// Fail late (server waits until stream is complete to reject) // Fail late (server waits until stream is complete to reject)
h = &handler{reqMessages: []string{payload1, payload2, payload3}} h = &handler{reqMessages: []string{payload1, payload2, payload3}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingInputCall", makeHeaders(codes.Internal, true), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/StreamingInputCall", makeHeaders(codes.Internal, true), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -395,7 +395,7 @@ func doTestServerStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSour
// Success // Success
h := &handler{reqMessages: []string{payload}} h := &handler{reqMessages: []string{payload}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingOutputCall", makeHeaders(codes.OK), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/StreamingOutputCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -418,7 +418,7 @@ func doTestServerStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSour
// Fail fast (server rejects as soon as possible) // Fail fast (server rejects as soon as possible)
h = &handler{reqMessages: []string{payload}} h = &handler{reqMessages: []string{payload}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingOutputCall", makeHeaders(codes.Aborted), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/StreamingOutputCall", makeHeaders(codes.Aborted), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -427,7 +427,7 @@ func doTestServerStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSour
// Fail late (server waits until stream is complete to reject) // Fail late (server waits until stream is complete to reject)
h = &handler{reqMessages: []string{payload}} h = &handler{reqMessages: []string{payload}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingOutputCall", makeHeaders(codes.AlreadyExists, true), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/StreamingOutputCall", makeHeaders(codes.AlreadyExists, true), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -448,7 +448,7 @@ func doTestHalfDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Success // Success
h := &handler{reqMessages: reqs} h := &handler{reqMessages: reqs}
err := InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/HalfDuplexCall", makeHeaders(codes.OK), h, h.getRequestData) err := InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/HalfDuplexCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -463,7 +463,7 @@ func doTestHalfDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Fail fast (server rejects as soon as possible) // Fail fast (server rejects as soon as possible)
h = &handler{reqMessages: reqs} h = &handler{reqMessages: reqs}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/HalfDuplexCall", makeHeaders(codes.Canceled), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/HalfDuplexCall", makeHeaders(codes.Canceled), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -472,7 +472,7 @@ func doTestHalfDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Fail late (server waits until stream is complete to reject) // Fail late (server waits until stream is complete to reject)
h = &handler{reqMessages: reqs} h = &handler{reqMessages: reqs}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/HalfDuplexCall", makeHeaders(codes.DataLoss, true), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/HalfDuplexCall", makeHeaders(codes.DataLoss, true), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -504,7 +504,7 @@ func doTestFullDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Success // Success
h := &handler{reqMessages: reqs} h := &handler{reqMessages: reqs}
err := InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/FullDuplexCall", makeHeaders(codes.OK), h, h.getRequestData) err := InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/FullDuplexCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -535,7 +535,7 @@ func doTestFullDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Fail fast (server rejects as soon as possible) // Fail fast (server rejects as soon as possible)
h = &handler{reqMessages: reqs} h = &handler{reqMessages: reqs}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/FullDuplexCall", makeHeaders(codes.PermissionDenied), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/FullDuplexCall", makeHeaders(codes.PermissionDenied), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
@ -544,7 +544,7 @@ func doTestFullDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Fail late (server waits until stream is complete to reject) // Fail late (server waits until stream is complete to reject)
h = &handler{reqMessages: reqs} h = &handler{reqMessages: reqs}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/FullDuplexCall", makeHeaders(codes.ResourceExhausted, true), h, h.getRequestData) err = InvokeRPC(context.Background(), source, cc, "grpc.testing.TestService/FullDuplexCall", makeHeaders(codes.ResourceExhausted, true), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }

View File

@ -15,9 +15,10 @@ import (
"github.com/fullstorydev/grpcurl" "github.com/fullstorydev/grpcurl"
) )
// TestServer is the testserver instance
type TestServer struct{} type TestServer struct{}
// One empty request followed by one empty response. // EmptyCall is One empty request followed by one empty response.
func (TestServer) EmptyCall(ctx context.Context, req *grpc_testing.Empty) (*grpc_testing.Empty, error) { func (TestServer) EmptyCall(ctx context.Context, req *grpc_testing.Empty) (*grpc_testing.Empty, error) {
headers, trailers, failEarly, failLate := processMetadata(ctx) headers, trailers, failEarly, failLate := processMetadata(ctx)
grpc.SetHeader(ctx, headers) grpc.SetHeader(ctx, headers)
@ -32,7 +33,7 @@ func (TestServer) EmptyCall(ctx context.Context, req *grpc_testing.Empty) (*grpc
return req, nil return req, nil
} }
// One request followed by one response. // UnaryCall is One request followed by one response.
// The server returns the client payload as-is. // The server returns the client payload as-is.
func (TestServer) UnaryCall(ctx context.Context, req *grpc_testing.SimpleRequest) (*grpc_testing.SimpleResponse, error) { func (TestServer) UnaryCall(ctx context.Context, req *grpc_testing.SimpleRequest) (*grpc_testing.SimpleResponse, error) {
headers, trailers, failEarly, failLate := processMetadata(ctx) headers, trailers, failEarly, failLate := processMetadata(ctx)
@ -50,7 +51,7 @@ func (TestServer) UnaryCall(ctx context.Context, req *grpc_testing.SimpleRequest
}, nil }, nil
} }
// One request followed by a sequence of responses (streamed download). // StreamingOutputCall is One request followed by a sequence of responses (streamed download).
// The server returns the payload with client desired type and sizes. // The server returns the payload with client desired type and sizes.
func (TestServer) StreamingOutputCall(req *grpc_testing.StreamingOutputCallRequest, str grpc_testing.TestService_StreamingOutputCallServer) error { func (TestServer) StreamingOutputCall(req *grpc_testing.StreamingOutputCallRequest, str grpc_testing.TestService_StreamingOutputCallServer) error {
headers, trailers, failEarly, failLate := processMetadata(str.Context()) headers, trailers, failEarly, failLate := processMetadata(str.Context())
@ -87,7 +88,7 @@ func (TestServer) StreamingOutputCall(req *grpc_testing.StreamingOutputCallReque
return nil return nil
} }
// A sequence of requests followed by one response (streamed upload). // StreamingInputCall is A sequence of requests followed by one response (streamed upload).
// The server returns the aggregated size of client payload as the result. // The server returns the aggregated size of client payload as the result.
func (TestServer) StreamingInputCall(str grpc_testing.TestService_StreamingInputCallServer) error { func (TestServer) StreamingInputCall(str grpc_testing.TestService_StreamingInputCallServer) error {
headers, trailers, failEarly, failLate := processMetadata(str.Context()) headers, trailers, failEarly, failLate := processMetadata(str.Context())
@ -103,10 +104,10 @@ func (TestServer) StreamingInputCall(str grpc_testing.TestService_StreamingInput
return str.Context().Err() return str.Context().Err()
} }
if req, err := str.Recv(); err != nil { if req, err := str.Recv(); err != nil {
if err == io.EOF { if err != io.EOF {
break return err
} }
return err break
} else { } else {
sz += len(req.Payload.Body) sz += len(req.Payload.Body)
} }
@ -121,7 +122,7 @@ func (TestServer) StreamingInputCall(str grpc_testing.TestService_StreamingInput
return nil return nil
} }
// A sequence of requests with each request served by the server immediately. // FullDuplexCall is A sequence of requests with each request served by the server immediately.
// As one request could lead to multiple responses, this interface // As one request could lead to multiple responses, this interface
// demonstrates the idea of full duplexing. // demonstrates the idea of full duplexing.
func (TestServer) FullDuplexCall(str grpc_testing.TestService_FullDuplexCallServer) error { func (TestServer) FullDuplexCall(str grpc_testing.TestService_FullDuplexCallServer) error {
@ -163,7 +164,7 @@ func (TestServer) FullDuplexCall(str grpc_testing.TestService_FullDuplexCallServ
return nil return nil
} }
// A sequence of requests followed by a sequence of responses. // HalfDuplexCall is A sequence of requests followed by a sequence of responses.
// The server buffers all the client requests and then serves them in order. A // The server buffers all the client requests and then serves them in order. A
// stream of responses are returned to the client when the server starts with // stream of responses are returned to the client when the server starts with
// first request. // first request.
@ -181,10 +182,10 @@ func (TestServer) HalfDuplexCall(str grpc_testing.TestService_HalfDuplexCallServ
return str.Context().Err() return str.Context().Err()
} }
if req, err := str.Recv(); err != nil { if req, err := str.Recv(); err != nil {
if err == io.EOF { if err != io.EOF {
break return err
} }
return err break
} else { } else {
reqs = append(reqs, req) reqs = append(reqs, req)
} }
@ -203,6 +204,7 @@ func (TestServer) HalfDuplexCall(str grpc_testing.TestService_HalfDuplexCallServ
return nil return nil
} }
// Metadata const
const ( const (
MetadataReplyHeaders = "reply-with-headers" MetadataReplyHeaders = "reply-with-headers"
MetadataReplyTrailers = "reply-with-trailers" MetadataReplyTrailers = "reply-with-trailers"