From 50495c077cbfc4ef1e2fdf56cf20a641431cb676 Mon Sep 17 00:00:00 2001 From: Osama Abuelsorour Date: Wed, 7 Aug 2019 16:33:04 -0700 Subject: [PATCH 1/4] fix propagation of headers even with errors --- proxy/handler.go | 14 ++- proxy/handler_test.go | 34 ++++++ testservice/test.pb.go | 241 +++++++++++++++++++++++++++++++---------- testservice/test.proto | 2 + 4 files changed, 227 insertions(+), 64 deletions(-) diff --git a/proxy/handler.go b/proxy/handler.go index 752f892..5599804 100644 --- a/proxy/handler.go +++ b/proxy/handler.go @@ -116,13 +116,9 @@ func (s *handler) forwardClientToServer(src grpc.ClientStream, dst grpc.ServerSt go func() { f := &frame{} for i := 0; ; i++ { - if err := src.RecvMsg(f); err != nil { - ret <- err // this can be io.EOF which is happy case - break - } if i == 0 { - // This is a bit of a hack, but client to server headers are only readable after first client msg is - // received but must be written to server stream before the first msg is flushed. + // This is a bit of a hack, but client to server headers must be forwarded even in case of errors. + // and must be written to server stream before the first msg is flushed. // This is the only place to do it nicely. md, err := src.Header() if err != nil { @@ -134,6 +130,12 @@ func (s *handler) forwardClientToServer(src grpc.ClientStream, dst grpc.ServerSt break } } + + if err := src.RecvMsg(f); err != nil { + ret <- err // this can be io.EOF which is happy case + break + } + if err := dst.SendMsg(f); err != nil { ret <- err break diff --git a/proxy/handler_test.go b/proxy/handler_test.go index c811408..1dc9ffb 100644 --- a/proxy/handler_test.go +++ b/proxy/handler_test.go @@ -61,6 +61,8 @@ func (s *assertingService) Ping(ctx context.Context, ping *pb.PingRequest) (*pb. } func (s *assertingService) PingError(ctx context.Context, ping *pb.PingRequest) (*pb.Empty, error) { + // Send user headers. + grpc.SendHeader(ctx, metadata.Pairs(serverHeaderMdKey, "I like turtles.")) return nil, grpc.Errorf(codes.FailedPrecondition, "Userspace error.") } @@ -95,6 +97,12 @@ func (s *assertingService) PingStream(stream pb.TestService_PingStreamServer) er return nil } +func (s *assertingService) PingStreamError(stream pb.TestService_PingStreamErrorServer) error { + stream.SendHeader(metadata.Pairs(serverHeaderMdKey, "I like turtles.")) + + return grpc.Errorf(codes.FailedPrecondition, "Userspace error.") +} + // ProxyHappySuite tests the "happy" path of handling: that everything works in absence of connection issues. type ProxyHappySuite struct { suite.Suite @@ -139,6 +147,15 @@ func (s *ProxyHappySuite) TestPingCarriesServerHeadersAndTrailers() { assert.Len(s.T(), trailerMd, 1, "server response trailers must contain server data") } +func (s *ProxyHappySuite) TestPingCarriesServerHeadersWhenServerError() { + headerMd := metadata.Pairs("bar", "foo") + trailerMd := make(metadata.MD) + _, err := s.testClient.PingError(s.ctx(), &pb.PingRequest{Value: "foo"}, grpc.Header(&headerMd), grpc.Trailer(&trailerMd)) + require.Error(s.T(), err, "PingError should never succeed") + assert.Equal(s.T(), codes.FailedPrecondition, grpc.Code(err)) + assert.Contains(s.T(), headerMd, serverHeaderMdKey, "server response headers must contain server data") +} + func (s *ProxyHappySuite) TestPingErrorPropagatesAppError() { _, err := s.testClient.PingError(s.ctx(), &pb.PingRequest{Value: "foo"}) require.Error(s.T(), err, "PingError should never succeed") @@ -182,6 +199,23 @@ func (s *ProxyHappySuite) TestPingStream_FullDuplexWorks() { assert.Len(s.T(), trailerMd, 1, "PingList trailer headers user contain metadata") } +func (s *ProxyHappySuite) TestPingStream_FullDuplexWithErrorsAndMetadata() { + stream, err := s.testClient.PingStreamError(s.ctx()) + require.NoError(s.T(), err, "PingStream request should be successful.") + + ping := &pb.PingRequest{Value: "foo:1"} + require.NoError(s.T(), stream.Send(ping), "sending to PingStreamError must not fail") + // Check that the header arrives. + headerMd, err := stream.Header() + require.NoError(s.T(), err, "PingStream headers should not error.") + assert.Contains(s.T(), headerMd, serverHeaderMdKey, "PingStream response headers user contain metadata") + + _, err = stream.Recv() + assert.Equal(s.T(), codes.FailedPrecondition, grpc.Code(err)) + + require.NoError(s.T(), stream.CloseSend(), "no error on close send") +} + func (s *ProxyHappySuite) TestPingStream_StressTest() { for i := 0; i < 50; i++ { s.TestPingStream_FullDuplexWorks() diff --git a/testservice/test.pb.go b/testservice/test.pb.go index 1f1f482..e11b055 100644 --- a/testservice/test.pb.go +++ b/testservice/test.pb.go @@ -1,23 +1,13 @@ -// Code generated by protoc-gen-go. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: test.proto -// DO NOT EDIT! -/* -Package mwitkow_testproto is a generated protocol buffer package. - -It is generated from these files: - test.proto - -It has these top-level messages: - Empty - PingRequest - PingResponse -*/ package mwitkow_testproto -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) import ( context "golang.org/x/net/context" @@ -36,21 +26,67 @@ var _ = math.Inf const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type Empty struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Empty) Reset() { *m = Empty{} } -func (m *Empty) String() string { return proto.CompactTextString(m) } -func (*Empty) ProtoMessage() {} -func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (m *Empty) Reset() { *m = Empty{} } +func (m *Empty) String() string { return proto.CompactTextString(m) } +func (*Empty) ProtoMessage() {} +func (*Empty) Descriptor() ([]byte, []int) { + return fileDescriptor_c161fcfdc0c3ff1e, []int{0} +} + +func (m *Empty) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Empty.Unmarshal(m, b) +} +func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Empty.Marshal(b, m, deterministic) +} +func (m *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(m, src) +} +func (m *Empty) XXX_Size() int { + return xxx_messageInfo_Empty.Size(m) +} +func (m *Empty) XXX_DiscardUnknown() { + xxx_messageInfo_Empty.DiscardUnknown(m) +} + +var xxx_messageInfo_Empty proto.InternalMessageInfo type PingRequest struct { - Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PingRequest) Reset() { *m = PingRequest{} } +func (m *PingRequest) String() string { return proto.CompactTextString(m) } +func (*PingRequest) ProtoMessage() {} +func (*PingRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_c161fcfdc0c3ff1e, []int{1} +} + +func (m *PingRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PingRequest.Unmarshal(m, b) +} +func (m *PingRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PingRequest.Marshal(b, m, deterministic) +} +func (m *PingRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PingRequest.Merge(m, src) +} +func (m *PingRequest) XXX_Size() int { + return xxx_messageInfo_PingRequest.Size(m) +} +func (m *PingRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PingRequest.DiscardUnknown(m) } -func (m *PingRequest) Reset() { *m = PingRequest{} } -func (m *PingRequest) String() string { return proto.CompactTextString(m) } -func (*PingRequest) ProtoMessage() {} -func (*PingRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +var xxx_messageInfo_PingRequest proto.InternalMessageInfo func (m *PingRequest) GetValue() string { if m != nil { @@ -60,14 +96,37 @@ func (m *PingRequest) GetValue() string { } type PingResponse struct { - Value string `protobuf:"bytes,1,opt,name=Value" json:"Value,omitempty"` - Counter int32 `protobuf:"varint,2,opt,name=counter" json:"counter,omitempty"` + Value string `protobuf:"bytes,1,opt,name=Value,proto3" json:"Value,omitempty"` + Counter int32 `protobuf:"varint,2,opt,name=counter,proto3" json:"counter,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PingResponse) Reset() { *m = PingResponse{} } +func (m *PingResponse) String() string { return proto.CompactTextString(m) } +func (*PingResponse) ProtoMessage() {} +func (*PingResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_c161fcfdc0c3ff1e, []int{2} +} + +func (m *PingResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PingResponse.Unmarshal(m, b) +} +func (m *PingResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PingResponse.Marshal(b, m, deterministic) +} +func (m *PingResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PingResponse.Merge(m, src) +} +func (m *PingResponse) XXX_Size() int { + return xxx_messageInfo_PingResponse.Size(m) +} +func (m *PingResponse) XXX_DiscardUnknown() { + xxx_messageInfo_PingResponse.DiscardUnknown(m) } -func (m *PingResponse) Reset() { *m = PingResponse{} } -func (m *PingResponse) String() string { return proto.CompactTextString(m) } -func (*PingResponse) ProtoMessage() {} -func (*PingResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +var xxx_messageInfo_PingResponse proto.InternalMessageInfo func (m *PingResponse) GetValue() string { if m != nil { @@ -97,14 +156,16 @@ var _ grpc.ClientConn // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for TestService service - +// TestServiceClient is the client API for TestService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type TestServiceClient interface { PingEmpty(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*PingResponse, error) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) PingError(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*Empty, error) PingList(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (TestService_PingListClient, error) PingStream(ctx context.Context, opts ...grpc.CallOption) (TestService_PingStreamClient, error) + PingStreamError(ctx context.Context, opts ...grpc.CallOption) (TestService_PingStreamErrorClient, error) } type testServiceClient struct { @@ -117,7 +178,7 @@ func NewTestServiceClient(cc *grpc.ClientConn) TestServiceClient { func (c *testServiceClient) PingEmpty(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*PingResponse, error) { out := new(PingResponse) - err := grpc.Invoke(ctx, "/mwitkow.testproto.TestService/PingEmpty", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/mwitkow.testproto.TestService/PingEmpty", in, out, opts...) if err != nil { return nil, err } @@ -126,7 +187,7 @@ func (c *testServiceClient) PingEmpty(ctx context.Context, in *Empty, opts ...gr func (c *testServiceClient) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { out := new(PingResponse) - err := grpc.Invoke(ctx, "/mwitkow.testproto.TestService/Ping", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/mwitkow.testproto.TestService/Ping", in, out, opts...) if err != nil { return nil, err } @@ -135,7 +196,7 @@ func (c *testServiceClient) Ping(ctx context.Context, in *PingRequest, opts ...g func (c *testServiceClient) PingError(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*Empty, error) { out := new(Empty) - err := grpc.Invoke(ctx, "/mwitkow.testproto.TestService/PingError", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/mwitkow.testproto.TestService/PingError", in, out, opts...) if err != nil { return nil, err } @@ -143,7 +204,7 @@ func (c *testServiceClient) PingError(ctx context.Context, in *PingRequest, opts } func (c *testServiceClient) PingList(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (TestService_PingListClient, error) { - stream, err := grpc.NewClientStream(ctx, &_TestService_serviceDesc.Streams[0], c.cc, "/mwitkow.testproto.TestService/PingList", opts...) + stream, err := c.cc.NewStream(ctx, &_TestService_serviceDesc.Streams[0], "/mwitkow.testproto.TestService/PingList", opts...) if err != nil { return nil, err } @@ -175,7 +236,7 @@ func (x *testServicePingListClient) Recv() (*PingResponse, error) { } func (c *testServiceClient) PingStream(ctx context.Context, opts ...grpc.CallOption) (TestService_PingStreamClient, error) { - stream, err := grpc.NewClientStream(ctx, &_TestService_serviceDesc.Streams[1], c.cc, "/mwitkow.testproto.TestService/PingStream", opts...) + stream, err := c.cc.NewStream(ctx, &_TestService_serviceDesc.Streams[1], "/mwitkow.testproto.TestService/PingStream", opts...) if err != nil { return nil, err } @@ -205,14 +266,45 @@ func (x *testServicePingStreamClient) Recv() (*PingResponse, error) { return m, nil } -// Server API for TestService service +func (c *testServiceClient) PingStreamError(ctx context.Context, opts ...grpc.CallOption) (TestService_PingStreamErrorClient, error) { + stream, err := c.cc.NewStream(ctx, &_TestService_serviceDesc.Streams[2], "/mwitkow.testproto.TestService/PingStreamError", opts...) + if err != nil { + return nil, err + } + x := &testServicePingStreamErrorClient{stream} + return x, nil +} + +type TestService_PingStreamErrorClient interface { + Send(*PingRequest) error + Recv() (*PingResponse, error) + grpc.ClientStream +} + +type testServicePingStreamErrorClient struct { + grpc.ClientStream +} + +func (x *testServicePingStreamErrorClient) Send(m *PingRequest) error { + return x.ClientStream.SendMsg(m) +} +func (x *testServicePingStreamErrorClient) Recv() (*PingResponse, error) { + m := new(PingResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// TestServiceServer is the server API for TestService service. type TestServiceServer interface { PingEmpty(context.Context, *Empty) (*PingResponse, error) Ping(context.Context, *PingRequest) (*PingResponse, error) PingError(context.Context, *PingRequest) (*Empty, error) PingList(*PingRequest, TestService_PingListServer) error PingStream(TestService_PingStreamServer) error + PingStreamError(TestService_PingStreamErrorServer) error } func RegisterTestServiceServer(s *grpc.Server, srv TestServiceServer) { @@ -320,6 +412,32 @@ func (x *testServicePingStreamServer) Recv() (*PingRequest, error) { return m, nil } +func _TestService_PingStreamError_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(TestServiceServer).PingStreamError(&testServicePingStreamErrorServer{stream}) +} + +type TestService_PingStreamErrorServer interface { + Send(*PingResponse) error + Recv() (*PingRequest, error) + grpc.ServerStream +} + +type testServicePingStreamErrorServer struct { + grpc.ServerStream +} + +func (x *testServicePingStreamErrorServer) Send(m *PingResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *testServicePingStreamErrorServer) Recv() (*PingRequest, error) { + m := new(PingRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + var _TestService_serviceDesc = grpc.ServiceDesc{ ServiceName: "mwitkow.testproto.TestService", HandlerType: (*TestServiceServer)(nil), @@ -349,27 +467,34 @@ var _TestService_serviceDesc = grpc.ServiceDesc{ ServerStreams: true, ClientStreams: true, }, + { + StreamName: "PingStreamError", + Handler: _TestService_PingStreamError_Handler, + ServerStreams: true, + ClientStreams: true, + }, }, Metadata: "test.proto", } -func init() { proto.RegisterFile("test.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 237 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x8f, 0x31, 0x4b, 0xc4, 0x40, - 0x10, 0x85, 0x6f, 0xd5, 0x78, 0xde, 0x9c, 0x8d, 0x83, 0xc5, 0x62, 0xa1, 0xc7, 0xda, 0xa4, 0x5a, - 0x0e, 0xed, 0xed, 0x44, 0x05, 0x41, 0x49, 0xc4, 0xfe, 0x0c, 0x83, 0x2c, 0x9a, 0x6c, 0xdc, 0x9d, - 0x24, 0xf8, 0x33, 0xfc, 0xc7, 0xb2, 0x1b, 0x85, 0x80, 0x06, 0x2d, 0x52, 0xce, 0x7b, 0x1f, 0x8f, - 0x6f, 0x00, 0x98, 0x3c, 0xeb, 0xda, 0x59, 0xb6, 0x78, 0x50, 0x76, 0x86, 0x5f, 0x6c, 0xa7, 0x43, - 0x16, 0x23, 0x35, 0x87, 0xe4, 0xb2, 0xac, 0xf9, 0x5d, 0x9d, 0xc2, 0xf2, 0xde, 0x54, 0xcf, 0x19, - 0xbd, 0x35, 0xe4, 0x19, 0x0f, 0x21, 0x69, 0x37, 0xaf, 0x0d, 0x49, 0xb1, 0x12, 0xe9, 0x22, 0xeb, - 0x0f, 0x75, 0x01, 0xfb, 0x3d, 0xe4, 0x6b, 0x5b, 0x79, 0x0a, 0xd4, 0xe3, 0x90, 0x8a, 0x07, 0x4a, - 0x98, 0x17, 0xb6, 0xa9, 0x98, 0x9c, 0xdc, 0x5a, 0x89, 0x34, 0xc9, 0xbe, 0xcf, 0xb3, 0x8f, 0x6d, - 0x58, 0x3e, 0x90, 0xe7, 0x9c, 0x5c, 0x6b, 0x0a, 0xc2, 0x6b, 0x58, 0x84, 0xbd, 0x68, 0x80, 0x52, - 0xff, 0xd0, 0xd3, 0xb1, 0x39, 0x3a, 0xf9, 0xa5, 0x19, 0x7a, 0xa8, 0x19, 0xde, 0xc0, 0x4e, 0x48, - 0xf0, 0x78, 0x14, 0x8d, 0x7f, 0xfd, 0x67, 0xea, 0xea, 0x4b, 0xca, 0x39, 0xeb, 0xfe, 0xdc, 0x1b, - 0x95, 0x56, 0x33, 0xbc, 0x83, 0xbd, 0x80, 0xde, 0x1a, 0xcf, 0x13, 0x78, 0xad, 0x05, 0xe6, 0x00, - 0x21, 0xcb, 0xd9, 0xd1, 0xa6, 0x9c, 0x60, 0x32, 0x15, 0x6b, 0xf1, 0xb4, 0x1b, 0x9b, 0xf3, 0xcf, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x4a, 0xc0, 0x8e, 0xe7, 0x29, 0x02, 0x00, 0x00, +func init() { proto.RegisterFile("test.proto", fileDescriptor_c161fcfdc0c3ff1e) } + +var fileDescriptor_c161fcfdc0c3ff1e = []byte{ + // 248 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x8f, 0x41, 0x4b, 0xc3, 0x40, + 0x10, 0x85, 0xbb, 0x6a, 0xac, 0x9d, 0x0a, 0xe2, 0xe0, 0x61, 0xf1, 0xa0, 0x65, 0xbd, 0xe4, 0xb4, + 0x14, 0xbd, 0x7b, 0x13, 0x15, 0x04, 0x25, 0x11, 0xf1, 0x5a, 0xcb, 0x20, 0x8b, 0x26, 0x1b, 0x77, + 0x27, 0x2d, 0xfe, 0x66, 0xff, 0x84, 0xec, 0x46, 0x31, 0xa0, 0xc1, 0x1c, 0x72, 0x9c, 0xf7, 0x1e, + 0x1f, 0xdf, 0x00, 0x30, 0x79, 0xd6, 0x95, 0xb3, 0x6c, 0x71, 0xbf, 0x58, 0x1b, 0x7e, 0xb1, 0x6b, + 0x1d, 0xb2, 0x18, 0xa9, 0x31, 0x24, 0x17, 0x45, 0xc5, 0xef, 0xea, 0x04, 0xa6, 0x77, 0xa6, 0x7c, + 0xce, 0xe8, 0xad, 0x26, 0xcf, 0x78, 0x00, 0xc9, 0x6a, 0xf1, 0x5a, 0x93, 0x14, 0x33, 0x91, 0x4e, + 0xb2, 0xe6, 0x50, 0xe7, 0xb0, 0xdb, 0x8c, 0x7c, 0x65, 0x4b, 0x4f, 0x61, 0xf5, 0xd0, 0x5e, 0xc5, + 0x03, 0x25, 0x8c, 0x97, 0xb6, 0x2e, 0x99, 0x9c, 0xdc, 0x98, 0x89, 0x34, 0xc9, 0xbe, 0xcf, 0xd3, + 0x8f, 0x4d, 0x98, 0xde, 0x93, 0xe7, 0x9c, 0xdc, 0xca, 0x2c, 0x09, 0xaf, 0x60, 0x12, 0x78, 0xd1, + 0x00, 0xa5, 0xfe, 0xa5, 0xa7, 0x63, 0x73, 0x78, 0xfc, 0x47, 0xd3, 0xf6, 0x50, 0x23, 0xbc, 0x86, + 0xad, 0x90, 0xe0, 0x51, 0xe7, 0x34, 0xfe, 0xd5, 0x07, 0x75, 0xf9, 0x25, 0xe5, 0x9c, 0x75, 0xff, + 0xf2, 0x3a, 0xa5, 0xd5, 0x08, 0x6f, 0x61, 0x27, 0x4c, 0x6f, 0x8c, 0xe7, 0x01, 0xbc, 0xe6, 0x02, + 0x73, 0x80, 0x90, 0xe5, 0xec, 0x68, 0x51, 0x0c, 0x80, 0x4c, 0xc5, 0x5c, 0xe0, 0x23, 0xec, 0xfd, + 0x40, 0xfb, 0x3d, 0xdd, 0x8f, 0xfc, 0xb4, 0x1d, 0x9b, 0xb3, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x10, 0x02, 0xd5, 0x3d, 0x83, 0x02, 0x00, 0x00, } diff --git a/testservice/test.proto b/testservice/test.proto index 54e3cf5..98490c6 100644 --- a/testservice/test.proto +++ b/testservice/test.proto @@ -25,5 +25,7 @@ service TestService { rpc PingStream(stream PingRequest) returns (stream PingResponse) {} + rpc PingStreamError(stream PingRequest) returns (stream PingResponse) {} + } From 5ddc13453aac86df06530e757fca194ecd166ddf Mon Sep 17 00:00:00 2001 From: Osama Abuelsorour Date: Wed, 7 Aug 2019 16:37:19 -0700 Subject: [PATCH 2/4] minor error message fix --- proxy/handler_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/handler_test.go b/proxy/handler_test.go index 1dc9ffb..9263b84 100644 --- a/proxy/handler_test.go +++ b/proxy/handler_test.go @@ -207,8 +207,8 @@ func (s *ProxyHappySuite) TestPingStream_FullDuplexWithErrorsAndMetadata() { require.NoError(s.T(), stream.Send(ping), "sending to PingStreamError must not fail") // Check that the header arrives. headerMd, err := stream.Header() - require.NoError(s.T(), err, "PingStream headers should not error.") - assert.Contains(s.T(), headerMd, serverHeaderMdKey, "PingStream response headers user contain metadata") + require.NoError(s.T(), err, "PingStreamError headers should not error.") + assert.Contains(s.T(), headerMd, serverHeaderMdKey, "PingStreamError response headers user should contain metadata") _, err = stream.Recv() assert.Equal(s.T(), codes.FailedPrecondition, grpc.Code(err)) From 07403582ada8e1c16e8a32d507677262afb78b4f Mon Sep 17 00:00:00 2001 From: Osama Abuelsorour Date: Wed, 7 Aug 2019 16:42:58 -0700 Subject: [PATCH 3/4] update go version (was too old) --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1b38744..e65933e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ sudo: false language: go go: - - 1.7 - - 1.8 + - 1.10 install: - go get google.golang.org/grpc From cca28a838da53342519cdb9d35f32adf55b86098 Mon Sep 17 00:00:00 2001 From: Osama Abuelsorour Date: Wed, 7 Aug 2019 16:46:02 -0700 Subject: [PATCH 4/4] escape go version --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e65933e..c0f4563 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ sudo: false language: go go: - - 1.10 + - "1.10" install: - go get google.golang.org/grpc