From d4db8608f8f33f6b485d2e271decae037d1375da Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja Date: Fri, 19 Mar 2021 12:15:20 +0100 Subject: [PATCH 1/9] add: gogoreflection --- server/grpc/gogoreflection/doc.go | 5 + .../grpc/gogoreflection/serverreflection.go | 486 +++++++++++++++ .../gogoreflection/serverreflection_test.go | 568 ++++++++++++++++++ server/grpc/server.go | 4 +- 4 files changed, 1061 insertions(+), 2 deletions(-) create mode 100644 server/grpc/gogoreflection/doc.go create mode 100644 server/grpc/gogoreflection/serverreflection.go create mode 100644 server/grpc/gogoreflection/serverreflection_test.go diff --git a/server/grpc/gogoreflection/doc.go b/server/grpc/gogoreflection/doc.go new file mode 100644 index 000000000000..691e632d0ee1 --- /dev/null +++ b/server/grpc/gogoreflection/doc.go @@ -0,0 +1,5 @@ +// Package gogoreflection implements gRPC reflection for gogoproto consumers +// the normal reflection library does not work as it points to a different +// singleton registry. The API and codebase is taken from the official gRPC +// reflection repository. +package gogoreflection diff --git a/server/grpc/gogoreflection/serverreflection.go b/server/grpc/gogoreflection/serverreflection.go new file mode 100644 index 000000000000..1098780d0472 --- /dev/null +++ b/server/grpc/gogoreflection/serverreflection.go @@ -0,0 +1,486 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* +Package reflection implements server reflection service. + +The service implemented is defined in: +https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto. + +To register server reflection on a gRPC server: + import "google.golang.org/grpc/reflection" + + s := grpc.NewServer() + pb.RegisterYourOwnServer(s, &server{}) + + // Register reflection service on gRPC server. + reflection.Register(s) + + s.Serve(lis) + +*/ +package gogoreflection // import "google.golang.org/grpc/reflection" + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "reflect" + "sort" + "sync" + + "github.com/golang/protobuf/proto" + dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" + "google.golang.org/grpc/status" +) + +type serverReflectionServer struct { + rpb.UnimplementedServerReflectionServer + s *grpc.Server + + initSymbols sync.Once + serviceNames []string + symbols map[string]*dpb.FileDescriptorProto // map of fully-qualified names to files +} + +// Register registers the server reflection service on the given gRPC server. +func Register(s *grpc.Server) { + rpb.RegisterServerReflectionServer(s, &serverReflectionServer{ + s: s, + }) +} + +// protoMessage is used for type assertion on proto messages. +// Generated proto message implements function Descriptor(), but Descriptor() +// is not part of interface proto.Message. This interface is needed to +// call Descriptor(). +type protoMessage interface { + Descriptor() ([]byte, []int) +} + +func (s *serverReflectionServer) getSymbols() (svcNames []string, symbolIndex map[string]*dpb.FileDescriptorProto) { + s.initSymbols.Do(func() { + serviceInfo := s.s.GetServiceInfo() + + s.symbols = map[string]*dpb.FileDescriptorProto{} + s.serviceNames = make([]string, 0, len(serviceInfo)) + processed := map[string]struct{}{} + for svc, info := range serviceInfo { + s.serviceNames = append(s.serviceNames, svc) + fdenc, ok := parseMetadata(info.Metadata) + if !ok { + continue + } + fd, err := decodeFileDesc(fdenc) + if err != nil { + continue + } + s.processFile(fd, processed) + } + sort.Strings(s.serviceNames) + }) + + return s.serviceNames, s.symbols +} + +func (s *serverReflectionServer) processFile(fd *dpb.FileDescriptorProto, processed map[string]struct{}) { + filename := fd.GetName() + if _, ok := processed[filename]; ok { + return + } + processed[filename] = struct{}{} + + prefix := fd.GetPackage() + + for _, msg := range fd.MessageType { + s.processMessage(fd, prefix, msg) + } + for _, en := range fd.EnumType { + s.processEnum(fd, prefix, en) + } + for _, ext := range fd.Extension { + s.processField(fd, prefix, ext) + } + for _, svc := range fd.Service { + svcName := fqn(prefix, svc.GetName()) + s.symbols[svcName] = fd + for _, meth := range svc.Method { + name := fqn(svcName, meth.GetName()) + s.symbols[name] = fd + } + } + + for _, dep := range fd.Dependency { + fdenc := proto.FileDescriptor(dep) + fdDep, err := decodeFileDesc(fdenc) + if err != nil { + continue + } + s.processFile(fdDep, processed) + } +} + +func (s *serverReflectionServer) processMessage(fd *dpb.FileDescriptorProto, prefix string, msg *dpb.DescriptorProto) { + msgName := fqn(prefix, msg.GetName()) + s.symbols[msgName] = fd + + for _, nested := range msg.NestedType { + s.processMessage(fd, msgName, nested) + } + for _, en := range msg.EnumType { + s.processEnum(fd, msgName, en) + } + for _, ext := range msg.Extension { + s.processField(fd, msgName, ext) + } + for _, fld := range msg.Field { + s.processField(fd, msgName, fld) + } + for _, oneof := range msg.OneofDecl { + oneofName := fqn(msgName, oneof.GetName()) + s.symbols[oneofName] = fd + } +} + +func (s *serverReflectionServer) processEnum(fd *dpb.FileDescriptorProto, prefix string, en *dpb.EnumDescriptorProto) { + enName := fqn(prefix, en.GetName()) + s.symbols[enName] = fd + + for _, val := range en.Value { + valName := fqn(enName, val.GetName()) + s.symbols[valName] = fd + } +} + +func (s *serverReflectionServer) processField(fd *dpb.FileDescriptorProto, prefix string, fld *dpb.FieldDescriptorProto) { + fldName := fqn(prefix, fld.GetName()) + s.symbols[fldName] = fd +} + +func fqn(prefix, name string) string { + if prefix == "" { + return name + } + return prefix + "." + name +} + +// fileDescForType gets the file descriptor for the given type. +// The given type should be a proto message. +func (s *serverReflectionServer) fileDescForType(st reflect.Type) (*dpb.FileDescriptorProto, error) { + m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(protoMessage) + if !ok { + return nil, fmt.Errorf("failed to create message from type: %v", st) + } + enc, _ := m.Descriptor() + + return decodeFileDesc(enc) +} + +// decodeFileDesc does decompression and unmarshalling on the given +// file descriptor byte slice. +func decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) { + raw, err := decompress(enc) + if err != nil { + return nil, fmt.Errorf("failed to decompress enc: %v", err) + } + + fd := new(dpb.FileDescriptorProto) + if err := proto.Unmarshal(raw, fd); err != nil { + return nil, fmt.Errorf("bad descriptor: %v", err) + } + return fd, nil +} + +// decompress does gzip decompression. +func decompress(b []byte) ([]byte, error) { + r, err := gzip.NewReader(bytes.NewReader(b)) + if err != nil { + return nil, fmt.Errorf("bad gzipped descriptor: %v", err) + } + out, err := ioutil.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("bad gzipped descriptor: %v", err) + } + return out, nil +} + +func typeForName(name string) (reflect.Type, error) { + pt := proto.MessageType(name) + if pt == nil { + return nil, fmt.Errorf("unknown type: %q", name) + } + st := pt.Elem() + + return st, nil +} + +func fileDescContainingExtension(st reflect.Type, ext int32) (*dpb.FileDescriptorProto, error) { + m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message) + if !ok { + return nil, fmt.Errorf("failed to create message from type: %v", st) + } + + var extDesc *proto.ExtensionDesc + for id, desc := range proto.RegisteredExtensions(m) { + if id == ext { + extDesc = desc + break + } + } + + if extDesc == nil { + return nil, fmt.Errorf("failed to find registered extension for extension number %v", ext) + } + + return decodeFileDesc(proto.FileDescriptor(extDesc.Filename)) +} + +func (s *serverReflectionServer) allExtensionNumbersForType(st reflect.Type) ([]int32, error) { + m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message) + if !ok { + return nil, fmt.Errorf("failed to create message from type: %v", st) + } + + exts := proto.RegisteredExtensions(m) + out := make([]int32, 0, len(exts)) + for id := range exts { + out = append(out, id) + } + return out, nil +} + +// fileDescWithDependencies returns a slice of serialized fileDescriptors in +// wire format ([]byte). The fileDescriptors will include fd and all the +// transitive dependencies of fd with names not in sentFileDescriptors. +func fileDescWithDependencies(fd *dpb.FileDescriptorProto, sentFileDescriptors map[string]bool) ([][]byte, error) { + r := [][]byte{} + queue := []*dpb.FileDescriptorProto{fd} + for len(queue) > 0 { + currentfd := queue[0] + queue = queue[1:] + if sent := sentFileDescriptors[currentfd.GetName()]; len(r) == 0 || !sent { + sentFileDescriptors[currentfd.GetName()] = true + currentfdEncoded, err := proto.Marshal(currentfd) + if err != nil { + return nil, err + } + r = append(r, currentfdEncoded) + } + for _, dep := range currentfd.Dependency { + fdenc := proto.FileDescriptor(dep) + fdDep, err := decodeFileDesc(fdenc) + if err != nil { + continue + } + queue = append(queue, fdDep) + } + } + return r, nil +} + +// fileDescEncodingByFilename finds the file descriptor for given filename, +// finds all of its previously unsent transitive dependencies, does marshalling +// on them, and returns the marshalled result. +func (s *serverReflectionServer) fileDescEncodingByFilename(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { + enc := proto.FileDescriptor(name) + if enc == nil { + return nil, fmt.Errorf("unknown file: %v", name) + } + fd, err := decodeFileDesc(enc) + if err != nil { + return nil, err + } + return fileDescWithDependencies(fd, sentFileDescriptors) +} + +// parseMetadata finds the file descriptor bytes specified meta. +// For SupportPackageIsVersion4, m is the name of the proto file, we +// call proto.FileDescriptor to get the byte slice. +// For SupportPackageIsVersion3, m is a byte slice itself. +func parseMetadata(meta interface{}) ([]byte, bool) { + // Check if meta is the file name. + if fileNameForMeta, ok := meta.(string); ok { + return proto.FileDescriptor(fileNameForMeta), true + } + + // Check if meta is the byte slice. + if enc, ok := meta.([]byte); ok { + return enc, true + } + + return nil, false +} + +// fileDescEncodingContainingSymbol finds the file descriptor containing the +// given symbol, finds all of its previously unsent transitive dependencies, +// does marshalling on them, and returns the marshalled result. The given symbol +// can be a type, a service or a method. +func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { + _, symbols := s.getSymbols() + fd := symbols[name] + if fd == nil { + // Check if it's a type name that was not present in the + // transitive dependencies of the registered services. + if st, err := typeForName(name); err == nil { + fd, err = s.fileDescForType(st) + if err != nil { + return nil, err + } + } + } + + if fd == nil { + return nil, fmt.Errorf("unknown symbol: %v", name) + } + + return fileDescWithDependencies(fd, sentFileDescriptors) +} + +// fileDescEncodingContainingExtension finds the file descriptor containing +// given extension, finds all of its previously unsent transitive dependencies, +// does marshalling on them, and returns the marshalled result. +func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName string, extNum int32, sentFileDescriptors map[string]bool) ([][]byte, error) { + st, err := typeForName(typeName) + if err != nil { + return nil, err + } + fd, err := fileDescContainingExtension(st, extNum) + if err != nil { + return nil, err + } + return fileDescWithDependencies(fd, sentFileDescriptors) +} + +// allExtensionNumbersForTypeName returns all extension numbers for the given type. +func (s *serverReflectionServer) allExtensionNumbersForTypeName(name string) ([]int32, error) { + st, err := typeForName(name) + if err != nil { + return nil, err + } + extNums, err := s.allExtensionNumbersForType(st) + if err != nil { + return nil, err + } + return extNums, nil +} + +// ServerReflectionInfo is the reflection service handler. +func (s *serverReflectionServer) ServerReflectionInfo(stream rpb.ServerReflection_ServerReflectionInfoServer) error { + sentFileDescriptors := make(map[string]bool) + for { + in, err := stream.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + + out := &rpb.ServerReflectionResponse{ + ValidHost: in.Host, + OriginalRequest: in, + } + switch req := in.MessageRequest.(type) { + case *rpb.ServerReflectionRequest_FileByFilename: + b, err := s.fileDescEncodingByFilename(req.FileByFilename, sentFileDescriptors) + if err != nil { + out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &rpb.ErrorResponse{ + ErrorCode: int32(codes.NotFound), + ErrorMessage: err.Error(), + }, + } + } else { + out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, + } + } + case *rpb.ServerReflectionRequest_FileContainingSymbol: + b, err := s.fileDescEncodingContainingSymbol(req.FileContainingSymbol, sentFileDescriptors) + if err != nil { + out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &rpb.ErrorResponse{ + ErrorCode: int32(codes.NotFound), + ErrorMessage: err.Error(), + }, + } + } else { + out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, + } + } + case *rpb.ServerReflectionRequest_FileContainingExtension: + typeName := req.FileContainingExtension.ContainingType + extNum := req.FileContainingExtension.ExtensionNumber + b, err := s.fileDescEncodingContainingExtension(typeName, extNum, sentFileDescriptors) + if err != nil { + out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &rpb.ErrorResponse{ + ErrorCode: int32(codes.NotFound), + ErrorMessage: err.Error(), + }, + } + } else { + out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, + } + } + case *rpb.ServerReflectionRequest_AllExtensionNumbersOfType: + extNums, err := s.allExtensionNumbersForTypeName(req.AllExtensionNumbersOfType) + if err != nil { + out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &rpb.ErrorResponse{ + ErrorCode: int32(codes.NotFound), + ErrorMessage: err.Error(), + }, + } + } else { + out.MessageResponse = &rpb.ServerReflectionResponse_AllExtensionNumbersResponse{ + AllExtensionNumbersResponse: &rpb.ExtensionNumberResponse{ + BaseTypeName: req.AllExtensionNumbersOfType, + ExtensionNumber: extNums, + }, + } + } + case *rpb.ServerReflectionRequest_ListServices: + svcNames, _ := s.getSymbols() + serviceResponses := make([]*rpb.ServiceResponse, len(svcNames)) + for i, n := range svcNames { + serviceResponses[i] = &rpb.ServiceResponse{ + Name: n, + } + } + out.MessageResponse = &rpb.ServerReflectionResponse_ListServicesResponse{ + ListServicesResponse: &rpb.ListServiceResponse{ + Service: serviceResponses, + }, + } + default: + return status.Errorf(codes.InvalidArgument, "invalid MessageRequest: %v", in.MessageRequest) + } + + if err := stream.Send(out); err != nil { + return err + } + } +} diff --git a/server/grpc/gogoreflection/serverreflection_test.go b/server/grpc/gogoreflection/serverreflection_test.go new file mode 100644 index 000000000000..76620f7f522a --- /dev/null +++ b/server/grpc/gogoreflection/serverreflection_test.go @@ -0,0 +1,568 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package gogoreflection + +/* +import ( + "context" + "fmt" + "net" + "reflect" + "sort" + "testing" + + "github.com/gogo/protobuf/proto" + dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + "google.golang.org/grpc" + rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" + pb "google.golang.org/grpc/reflection/grpc_testing" + pbv3 "google.golang.org/grpc/reflection/grpc_testingv3" +) + +var ( + s = &serverReflectionServer{} + // fileDescriptor of each test proto file. + fdTest *dpb.FileDescriptorProto + fdTestv3 *dpb.FileDescriptorProto + fdProto2 *dpb.FileDescriptorProto + fdProto2Ext *dpb.FileDescriptorProto + fdProto2Ext2 *dpb.FileDescriptorProto + // fileDescriptor marshalled. + fdTestByte []byte + fdTestv3Byte []byte + fdProto2Byte []byte + fdProto2ExtByte []byte + fdProto2Ext2Byte []byte +) + +type x struct { + grpctest.Tester +} + +func Test(t *testing.T) { + grpctest.RunSubTests(t, x{}) +} + +func loadFileDesc(filename string) (*dpb.FileDescriptorProto, []byte) { + enc := proto.FileDescriptor(filename) + if enc == nil { + panic(fmt.Sprintf("failed to find fd for file: %v", filename)) + } + fd, err := decodeFileDesc(enc) + if err != nil { + panic(fmt.Sprintf("failed to decode enc: %v", err)) + } + b, err := proto.Marshal(fd) + if err != nil { + panic(fmt.Sprintf("failed to marshal fd: %v", err)) + } + return fd, b +} + +func init() { + fdTest, fdTestByte = loadFileDesc("reflection/grpc_testing/test.proto") + fdTestv3, fdTestv3Byte = loadFileDesc("testv3.proto") + fdProto2, fdProto2Byte = loadFileDesc("reflection/grpc_testing/proto2.proto") + fdProto2Ext, fdProto2ExtByte = loadFileDesc("reflection/grpc_testing/proto2_ext.proto") + fdProto2Ext2, fdProto2Ext2Byte = loadFileDesc("reflection/grpc_testing/proto2_ext2.proto") +} + +func (x) TestFileDescForType(t *testing.T) { + for _, test := range []struct { + st reflect.Type + wantFd *dpb.FileDescriptorProto + }{ + {reflect.TypeOf(pb.SearchResponse_Result{}), fdTest}, + {reflect.TypeOf(pb.ToBeExtended{}), fdProto2}, + } { + fd, err := s.fileDescForType(test.st) + if err != nil || !proto.Equal(fd, test.wantFd) { + t.Errorf("fileDescForType(%q) = %q, %v, want %q, ", test.st, fd, err, test.wantFd) + } + } +} + +func (x) TestTypeForName(t *testing.T) { + for _, test := range []struct { + name string + want reflect.Type + }{ + {"grpc.testing.SearchResponse", reflect.TypeOf(pb.SearchResponse{})}, + } { + r, err := typeForName(test.name) + if err != nil || r != test.want { + t.Errorf("typeForName(%q) = %q, %v, want %q, ", test.name, r, err, test.want) + } + } +} + +func (x) TestTypeForNameNotFound(t *testing.T) { + for _, test := range []string{ + "grpc.testing.not_exiting", + } { + _, err := typeForName(test) + if err == nil { + t.Errorf("typeForName(%q) = _, %v, want _, ", test, err) + } + } +} + +func (x) TestFileDescContainingExtension(t *testing.T) { + for _, test := range []struct { + st reflect.Type + extNum int32 + want *dpb.FileDescriptorProto + }{ + {reflect.TypeOf(pb.ToBeExtended{}), 13, fdProto2Ext}, + {reflect.TypeOf(pb.ToBeExtended{}), 17, fdProto2Ext}, + {reflect.TypeOf(pb.ToBeExtended{}), 19, fdProto2Ext}, + {reflect.TypeOf(pb.ToBeExtended{}), 23, fdProto2Ext2}, + {reflect.TypeOf(pb.ToBeExtended{}), 29, fdProto2Ext2}, + } { + fd, err := fileDescContainingExtension(test.st, test.extNum) + if err != nil || !proto.Equal(fd, test.want) { + t.Errorf("fileDescContainingExtension(%q) = %q, %v, want %q, ", test.st, fd, err, test.want) + } + } +} + +// intArray is used to sort []int32 +type intArray []int32 + +func (s intArray) Len() int { return len(s) } +func (s intArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s intArray) Less(i, j int) bool { return s[i] < s[j] } + +func (x) TestAllExtensionNumbersForType(t *testing.T) { + for _, test := range []struct { + st reflect.Type + want []int32 + }{ + {reflect.TypeOf(pb.ToBeExtended{}), []int32{13, 17, 19, 23, 29}}, + } { + r, err := s.allExtensionNumbersForType(test.st) + sort.Sort(intArray(r)) + if err != nil || !reflect.DeepEqual(r, test.want) { + t.Errorf("allExtensionNumbersForType(%q) = %v, %v, want %v, ", test.st, r, err, test.want) + } + } +} + +// Do end2end tests. + +type server struct { + pb.UnimplementedSearchServiceServer +} + +func (s *server) Search(ctx context.Context, in *pb.SearchRequest) (*pb.SearchResponse, error) { + return &pb.SearchResponse{}, nil +} + +func (s *server) StreamingSearch(stream pb.SearchService_StreamingSearchServer) error { + return nil +} + +type serverV3 struct{} + +func (s *serverV3) Search(ctx context.Context, in *pbv3.SearchRequestV3) (*pbv3.SearchResponseV3, error) { + return &pbv3.SearchResponseV3{}, nil +} + +func (s *serverV3) StreamingSearch(stream pbv3.SearchServiceV3_StreamingSearchServer) error { + return nil +} + +func (x) TestReflectionEnd2end(t *testing.T) { + // Start server. + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen: %v", err) + } + s := grpc.NewServer() + pb.RegisterSearchServiceServer(s, &server{}) + pbv3.RegisterSearchServiceV3Server(s, &serverV3{}) + // Register reflection service on s. + Register(s) + go s.Serve(lis) + + // Create client. + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + t.Fatalf("cannot connect to server: %v", err) + } + defer conn.Close() + + c := rpb.NewServerReflectionClient(conn) + stream, err := c.ServerReflectionInfo(context.Background(), grpc.WaitForReady(true)) + if err != nil { + t.Fatalf("cannot get ServerReflectionInfo: %v", err) + } + + testFileByFilenameTransitiveClosure(t, stream, true) + testFileByFilenameTransitiveClosure(t, stream, false) + testFileByFilename(t, stream) + testFileByFilenameError(t, stream) + testFileContainingSymbol(t, stream) + testFileContainingSymbolError(t, stream) + testFileContainingExtension(t, stream) + testFileContainingExtensionError(t, stream) + testAllExtensionNumbersOfType(t, stream) + testAllExtensionNumbersOfTypeError(t, stream) + testListServices(t, stream) + + s.Stop() +} + +func testFileByFilenameTransitiveClosure(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient, expectClosure bool) { + filename := "reflection/grpc_testing/proto2_ext2.proto" + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_FileByFilename{ + FileByFilename: filename, + }, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_FileDescriptorResponse: + if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[0], fdProto2Ext2Byte) { + t.Errorf("FileByFilename(%v)\nreceived: %q,\nwant: %q", filename, r.GetFileDescriptorResponse().FileDescriptorProto[0], fdProto2Ext2Byte) + } + if expectClosure { + if len(r.GetFileDescriptorResponse().FileDescriptorProto) != 2 { + t.Errorf("FileByFilename(%v) returned %v file descriptors, expected 2", filename, len(r.GetFileDescriptorResponse().FileDescriptorProto)) + } else if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[1], fdProto2Byte) { + t.Errorf("FileByFilename(%v)\nreceived: %q,\nwant: %q", filename, r.GetFileDescriptorResponse().FileDescriptorProto[1], fdProto2Byte) + } + } else if len(r.GetFileDescriptorResponse().FileDescriptorProto) != 1 { + t.Errorf("FileByFilename(%v) returned %v file descriptors, expected 1", filename, len(r.GetFileDescriptorResponse().FileDescriptorProto)) + } + default: + t.Errorf("FileByFilename(%v) = %v, want type ", filename, r.MessageResponse) + } +} + +func testFileByFilename(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { + for _, test := range []struct { + filename string + want []byte + }{ + {"reflection/grpc_testing/test.proto", fdTestByte}, + {"reflection/grpc_testing/proto2.proto", fdProto2Byte}, + {"reflection/grpc_testing/proto2_ext.proto", fdProto2ExtByte}, + } { + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_FileByFilename{ + FileByFilename: test.filename, + }, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_FileDescriptorResponse: + if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) { + t.Errorf("FileByFilename(%v)\nreceived: %q,\nwant: %q", test.filename, r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) + } + default: + t.Errorf("FileByFilename(%v) = %v, want type ", test.filename, r.MessageResponse) + } + } +} + +func testFileByFilenameError(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { + for _, test := range []string{ + "test.poto", + "proo2.proto", + "proto2_et.proto", + } { + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_FileByFilename{ + FileByFilename: test, + }, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_ErrorResponse: + default: + t.Errorf("FileByFilename(%v) = %v, want type ", test, r.MessageResponse) + } + } +} + +func testFileContainingSymbol(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { + for _, test := range []struct { + symbol string + want []byte + }{ + {"grpc.testing.SearchService", fdTestByte}, + {"grpc.testing.SearchService.Search", fdTestByte}, + {"grpc.testing.SearchService.StreamingSearch", fdTestByte}, + {"grpc.testing.SearchResponse", fdTestByte}, + {"grpc.testing.ToBeExtended", fdProto2Byte}, + // Test support package v3. + {"grpc.testingv3.SearchServiceV3", fdTestv3Byte}, + {"grpc.testingv3.SearchServiceV3.Search", fdTestv3Byte}, + {"grpc.testingv3.SearchServiceV3.StreamingSearch", fdTestv3Byte}, + {"grpc.testingv3.SearchResponseV3", fdTestv3Byte}, + // search for field, oneof, enum, and enum value symbols, too + {"grpc.testingv3.SearchResponseV3.Result.snippets", fdTestv3Byte}, + {"grpc.testingv3.SearchResponseV3.Result.Value.val", fdTestv3Byte}, + {"grpc.testingv3.SearchResponseV3.Result.Value.str", fdTestv3Byte}, + {"grpc.testingv3.SearchResponseV3.State", fdTestv3Byte}, + {"grpc.testingv3.SearchResponseV3.State.FRESH", fdTestv3Byte}, + } { + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_FileContainingSymbol{ + FileContainingSymbol: test.symbol, + }, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_FileDescriptorResponse: + if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) { + t.Errorf("FileContainingSymbol(%v)\nreceived: %q,\nwant: %q", test.symbol, r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) + } + default: + t.Errorf("FileContainingSymbol(%v) = %v, want type ", test.symbol, r.MessageResponse) + } + } +} + +func testFileContainingSymbolError(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { + for _, test := range []string{ + "grpc.testing.SerchService", + "grpc.testing.SearchService.SearchE", + "grpc.tesing.SearchResponse", + "gpc.testing.ToBeExtended", + } { + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_FileContainingSymbol{ + FileContainingSymbol: test, + }, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_ErrorResponse: + default: + t.Errorf("FileContainingSymbol(%v) = %v, want type ", test, r.MessageResponse) + } + } +} + +func testFileContainingExtension(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { + for _, test := range []struct { + typeName string + extNum int32 + want []byte + }{ + {"grpc.testing.ToBeExtended", 13, fdProto2ExtByte}, + {"grpc.testing.ToBeExtended", 17, fdProto2ExtByte}, + {"grpc.testing.ToBeExtended", 19, fdProto2ExtByte}, + {"grpc.testing.ToBeExtended", 23, fdProto2Ext2Byte}, + {"grpc.testing.ToBeExtended", 29, fdProto2Ext2Byte}, + } { + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_FileContainingExtension{ + FileContainingExtension: &rpb.ExtensionRequest{ + ContainingType: test.typeName, + ExtensionNumber: test.extNum, + }, + }, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_FileDescriptorResponse: + if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) { + t.Errorf("FileContainingExtension(%v, %v)\nreceived: %q,\nwant: %q", test.typeName, test.extNum, r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) + } + default: + t.Errorf("FileContainingExtension(%v, %v) = %v, want type ", test.typeName, test.extNum, r.MessageResponse) + } + } +} + +func testFileContainingExtensionError(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { + for _, test := range []struct { + typeName string + extNum int32 + }{ + {"grpc.testing.ToBExtended", 17}, + {"grpc.testing.ToBeExtended", 15}, + } { + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_FileContainingExtension{ + FileContainingExtension: &rpb.ExtensionRequest{ + ContainingType: test.typeName, + ExtensionNumber: test.extNum, + }, + }, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_ErrorResponse: + default: + t.Errorf("FileContainingExtension(%v, %v) = %v, want type ", test.typeName, test.extNum, r.MessageResponse) + } + } +} + +func testAllExtensionNumbersOfType(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { + for _, test := range []struct { + typeName string + want []int32 + }{ + {"grpc.testing.ToBeExtended", []int32{13, 17, 19, 23, 29}}, + } { + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_AllExtensionNumbersOfType{ + AllExtensionNumbersOfType: test.typeName, + }, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_AllExtensionNumbersResponse: + extNum := r.GetAllExtensionNumbersResponse().ExtensionNumber + sort.Sort(intArray(extNum)) + if r.GetAllExtensionNumbersResponse().BaseTypeName != test.typeName || + !reflect.DeepEqual(extNum, test.want) { + t.Errorf("AllExtensionNumbersOfType(%v)\nreceived: %v,\nwant: {%q %v}", r.GetAllExtensionNumbersResponse(), test.typeName, test.typeName, test.want) + } + default: + t.Errorf("AllExtensionNumbersOfType(%v) = %v, want type ", test.typeName, r.MessageResponse) + } + } +} + +func testAllExtensionNumbersOfTypeError(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { + for _, test := range []string{ + "grpc.testing.ToBeExtendedE", + } { + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_AllExtensionNumbersOfType{ + AllExtensionNumbersOfType: test, + }, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_ErrorResponse: + default: + t.Errorf("AllExtensionNumbersOfType(%v) = %v, want type ", test, r.MessageResponse) + } + } +} + +func testListServices(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { + if err := stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_ListServices{}, + }); err != nil { + t.Fatalf("failed to send request: %v", err) + } + r, err := stream.Recv() + if err != nil { + // io.EOF is not ok. + t.Fatalf("failed to recv response: %v", err) + } + + switch r.MessageResponse.(type) { + case *rpb.ServerReflectionResponse_ListServicesResponse: + services := r.GetListServicesResponse().Service + want := []string{ + "grpc.testingv3.SearchServiceV3", + "grpc.testing.SearchService", + "grpc.reflection.v1alpha.ServerReflection", + } + // Compare service names in response with want. + if len(services) != len(want) { + t.Errorf("= %v, want service names: %v", services, want) + } + m := make(map[string]int) + for _, e := range services { + m[e.Name]++ + } + for _, e := range want { + if m[e] > 0 { + m[e]-- + continue + } + t.Errorf("ListService\nreceived: %v,\nwant: %q", services, want) + } + default: + t.Errorf("ListServices = %v, want type ", r.MessageResponse) + } +} +*/ diff --git a/server/grpc/server.go b/server/grpc/server.go index d9d0be1a032c..1d001e235c3e 100644 --- a/server/grpc/server.go +++ b/server/grpc/server.go @@ -6,9 +6,9 @@ import ( "time" "google.golang.org/grpc" - "google.golang.org/grpc/reflection" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/server/grpc/gogoreflection" "github.com/cosmos/cosmos-sdk/server/types" ) @@ -19,7 +19,7 @@ func StartGRPCServer(clientCtx client.Context, app types.Application, address st // Reflection allows external clients to see what services and methods // the gRPC server exposes. - reflection.Register(grpcSrv) + gogoreflection.Register(grpcSrv) listener, err := net.Listen("tcp", address) if err != nil { From 5c11486817d9b79a448266a8adf6933380336924 Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja Date: Fri, 19 Mar 2021 16:27:54 +0100 Subject: [PATCH 2/9] fix: server reflection --- .../grpc/gogoreflection/fix_registration.go | 96 +++ .../gogoreflection/fix_registration_test.go | 22 + .../grpc/gogoreflection/serverreflection.go | 22 +- .../gogoreflection/serverreflection_test.go | 568 ------------------ server/grpc/server_test.go | 21 +- 5 files changed, 146 insertions(+), 583 deletions(-) create mode 100644 server/grpc/gogoreflection/fix_registration.go create mode 100644 server/grpc/gogoreflection/fix_registration_test.go delete mode 100644 server/grpc/gogoreflection/serverreflection_test.go diff --git a/server/grpc/gogoreflection/fix_registration.go b/server/grpc/gogoreflection/fix_registration.go new file mode 100644 index 000000000000..0dfa0d7d73b7 --- /dev/null +++ b/server/grpc/gogoreflection/fix_registration.go @@ -0,0 +1,96 @@ +package gogoreflection + +import ( + "bytes" + "compress/gzip" + "fmt" + "log" + "reflect" + + _ "github.com/gogo/protobuf/gogoproto" // required so it does register the gogoproto file descriptor + gogoproto "github.com/gogo/protobuf/proto" + "github.com/golang/protobuf/proto" + dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + _ "github.com/regen-network/cosmos-proto" // look above +) + +var importsToFix = map[string]string{ + "gogo.proto": "gogoproto/gogo.proto", + "cosmos.proto": "cosmos_proto/cosmos.proto", +} + +// fixRegistration is required because certain files register themselves in a way +// but are imported by other files in a different way. +// NOTE(fdymylja): This fix should not be needed and should be addressed in some CI. +// Currently every cosmos-sdk proto file is importing gogo.proto as gogoproto/gogo.proto, +// but gogo.proto registers itself as gogo.proto, same goes for cosmos.proto. +func fixRegistration(registeredAs, importedAs string) error { + raw := gogoproto.FileDescriptor(registeredAs) + if len(raw) == 0 { + return fmt.Errorf("file descriptor not found: %s", registeredAs) + } + + fd, err := decodeFileDesc(raw) + if err != nil { + return err + } + + // fix name + *fd.Name = importedAs + fixedRaw, err := compress(fd) + if err != nil { + return fmt.Errorf("unable to compress: %w", err) + } + gogoproto.RegisterFile(importedAs, fixedRaw) + return nil +} + +func init() { + // we need to fix the gogoproto filedesc to match the import path + // in theory this shouldn't be required, generally speaking + // proto files should be imported as their registration path + + for registeredAs, importedAs := range importsToFix { + err := fixRegistration(registeredAs, importedAs) + if err != nil { + panic(err) + } + } +} + +func compress(fd *dpb.FileDescriptorProto) ([]byte, error) { + fdBytes, err := proto.Marshal(fd) + if err != nil { + return nil, err + } + buf := new(bytes.Buffer) + cw := gzip.NewWriter(buf) + _, err = cw.Write(fdBytes) + if err != nil { + return nil, err + } + err = cw.Close() + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func getFileDescriptor(filePath string) []byte { + // since we got well known descriptors which are not registered into gogoproto registry + // but are instead registered into the proto one, we need to check both + fd := gogoproto.FileDescriptor(filePath) + if len(fd) != 0 { + return fd + } + return proto.FileDescriptor(filePath) +} + +func getMessageType(name string) reflect.Type { + log.Printf("asking for type: %s", name) + typ := gogoproto.MessageType(name) + if typ == nil { + log.Printf("failed type: %s", name) + } + return typ +} diff --git a/server/grpc/gogoreflection/fix_registration_test.go b/server/grpc/gogoreflection/fix_registration_test.go new file mode 100644 index 000000000000..0693556688e7 --- /dev/null +++ b/server/grpc/gogoreflection/fix_registration_test.go @@ -0,0 +1,22 @@ +package gogoreflection + +import ( + "testing" + + "google.golang.org/protobuf/runtime/protoimpl" +) + +func TestRegistrationFix(t *testing.T) { + res := getFileDescriptor("gogoproto/gogo.proto") + rawDesc, err := decompress(res) + if err != nil { + t.Fatal(err) + } + fd := protoimpl.DescBuilder{ + RawDescriptor: rawDesc, + }.Build() + + if fd.File.Extensions().Len() == 0 { + t.Fatal("unexpected parsing") + } +} diff --git a/server/grpc/gogoreflection/serverreflection.go b/server/grpc/gogoreflection/serverreflection.go index 1098780d0472..1a08fdd91f80 100644 --- a/server/grpc/gogoreflection/serverreflection.go +++ b/server/grpc/gogoreflection/serverreflection.go @@ -42,10 +42,12 @@ import ( "fmt" "io" "io/ioutil" + "log" "reflect" "sort" "sync" + gogoproto "github.com/gogo/protobuf/proto" "github.com/golang/protobuf/proto" dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" "google.golang.org/grpc" @@ -131,7 +133,7 @@ func (s *serverReflectionServer) processFile(fd *dpb.FileDescriptorProto, proces } for _, dep := range fd.Dependency { - fdenc := proto.FileDescriptor(dep) + fdenc := getFileDescriptor(dep) fdDep, err := decodeFileDesc(fdenc) if err != nil { continue @@ -225,7 +227,7 @@ func decompress(b []byte) ([]byte, error) { } func typeForName(name string) (reflect.Type, error) { - pt := proto.MessageType(name) + pt := getMessageType(name) if pt == nil { return nil, fmt.Errorf("unknown type: %q", name) } @@ -240,8 +242,8 @@ func fileDescContainingExtension(st reflect.Type, ext int32) (*dpb.FileDescripto return nil, fmt.Errorf("failed to create message from type: %v", st) } - var extDesc *proto.ExtensionDesc - for id, desc := range proto.RegisteredExtensions(m) { + var extDesc *gogoproto.ExtensionDesc + for id, desc := range gogoproto.RegisteredExtensions(m) { if id == ext { extDesc = desc break @@ -252,7 +254,7 @@ func fileDescContainingExtension(st reflect.Type, ext int32) (*dpb.FileDescripto return nil, fmt.Errorf("failed to find registered extension for extension number %v", ext) } - return decodeFileDesc(proto.FileDescriptor(extDesc.Filename)) + return decodeFileDesc(getFileDescriptor(extDesc.Filename)) } func (s *serverReflectionServer) allExtensionNumbersForType(st reflect.Type) ([]int32, error) { @@ -261,7 +263,7 @@ func (s *serverReflectionServer) allExtensionNumbersForType(st reflect.Type) ([] return nil, fmt.Errorf("failed to create message from type: %v", st) } - exts := proto.RegisteredExtensions(m) + exts := gogoproto.RegisteredExtensions(m) out := make([]int32, 0, len(exts)) for id := range exts { out = append(out, id) @@ -287,7 +289,7 @@ func fileDescWithDependencies(fd *dpb.FileDescriptorProto, sentFileDescriptors m r = append(r, currentfdEncoded) } for _, dep := range currentfd.Dependency { - fdenc := proto.FileDescriptor(dep) + fdenc := getFileDescriptor(dep) fdDep, err := decodeFileDesc(fdenc) if err != nil { continue @@ -302,7 +304,7 @@ func fileDescWithDependencies(fd *dpb.FileDescriptorProto, sentFileDescriptors m // finds all of its previously unsent transitive dependencies, does marshalling // on them, and returns the marshalled result. func (s *serverReflectionServer) fileDescEncodingByFilename(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { - enc := proto.FileDescriptor(name) + enc := getFileDescriptor(name) if enc == nil { return nil, fmt.Errorf("unknown file: %v", name) } @@ -320,7 +322,7 @@ func (s *serverReflectionServer) fileDescEncodingByFilename(name string, sentFil func parseMetadata(meta interface{}) ([]byte, bool) { // Check if meta is the file name. if fileNameForMeta, ok := meta.(string); ok { - return proto.FileDescriptor(fileNameForMeta), true + return getFileDescriptor(fileNameForMeta), true } // Check if meta is the byte slice. @@ -454,6 +456,7 @@ func (s *serverReflectionServer) ServerReflectionInfo(stream rpb.ServerReflectio ErrorMessage: err.Error(), }, } + log.Printf("OH NO: %s", err) } else { out.MessageResponse = &rpb.ServerReflectionResponse_AllExtensionNumbersResponse{ AllExtensionNumbersResponse: &rpb.ExtensionNumberResponse{ @@ -478,7 +481,6 @@ func (s *serverReflectionServer) ServerReflectionInfo(stream rpb.ServerReflectio default: return status.Errorf(codes.InvalidArgument, "invalid MessageRequest: %v", in.MessageRequest) } - if err := stream.Send(out); err != nil { return err } diff --git a/server/grpc/gogoreflection/serverreflection_test.go b/server/grpc/gogoreflection/serverreflection_test.go deleted file mode 100644 index 76620f7f522a..000000000000 --- a/server/grpc/gogoreflection/serverreflection_test.go +++ /dev/null @@ -1,568 +0,0 @@ -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package gogoreflection - -/* -import ( - "context" - "fmt" - "net" - "reflect" - "sort" - "testing" - - "github.com/gogo/protobuf/proto" - dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" - "google.golang.org/grpc" - rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" - pb "google.golang.org/grpc/reflection/grpc_testing" - pbv3 "google.golang.org/grpc/reflection/grpc_testingv3" -) - -var ( - s = &serverReflectionServer{} - // fileDescriptor of each test proto file. - fdTest *dpb.FileDescriptorProto - fdTestv3 *dpb.FileDescriptorProto - fdProto2 *dpb.FileDescriptorProto - fdProto2Ext *dpb.FileDescriptorProto - fdProto2Ext2 *dpb.FileDescriptorProto - // fileDescriptor marshalled. - fdTestByte []byte - fdTestv3Byte []byte - fdProto2Byte []byte - fdProto2ExtByte []byte - fdProto2Ext2Byte []byte -) - -type x struct { - grpctest.Tester -} - -func Test(t *testing.T) { - grpctest.RunSubTests(t, x{}) -} - -func loadFileDesc(filename string) (*dpb.FileDescriptorProto, []byte) { - enc := proto.FileDescriptor(filename) - if enc == nil { - panic(fmt.Sprintf("failed to find fd for file: %v", filename)) - } - fd, err := decodeFileDesc(enc) - if err != nil { - panic(fmt.Sprintf("failed to decode enc: %v", err)) - } - b, err := proto.Marshal(fd) - if err != nil { - panic(fmt.Sprintf("failed to marshal fd: %v", err)) - } - return fd, b -} - -func init() { - fdTest, fdTestByte = loadFileDesc("reflection/grpc_testing/test.proto") - fdTestv3, fdTestv3Byte = loadFileDesc("testv3.proto") - fdProto2, fdProto2Byte = loadFileDesc("reflection/grpc_testing/proto2.proto") - fdProto2Ext, fdProto2ExtByte = loadFileDesc("reflection/grpc_testing/proto2_ext.proto") - fdProto2Ext2, fdProto2Ext2Byte = loadFileDesc("reflection/grpc_testing/proto2_ext2.proto") -} - -func (x) TestFileDescForType(t *testing.T) { - for _, test := range []struct { - st reflect.Type - wantFd *dpb.FileDescriptorProto - }{ - {reflect.TypeOf(pb.SearchResponse_Result{}), fdTest}, - {reflect.TypeOf(pb.ToBeExtended{}), fdProto2}, - } { - fd, err := s.fileDescForType(test.st) - if err != nil || !proto.Equal(fd, test.wantFd) { - t.Errorf("fileDescForType(%q) = %q, %v, want %q, ", test.st, fd, err, test.wantFd) - } - } -} - -func (x) TestTypeForName(t *testing.T) { - for _, test := range []struct { - name string - want reflect.Type - }{ - {"grpc.testing.SearchResponse", reflect.TypeOf(pb.SearchResponse{})}, - } { - r, err := typeForName(test.name) - if err != nil || r != test.want { - t.Errorf("typeForName(%q) = %q, %v, want %q, ", test.name, r, err, test.want) - } - } -} - -func (x) TestTypeForNameNotFound(t *testing.T) { - for _, test := range []string{ - "grpc.testing.not_exiting", - } { - _, err := typeForName(test) - if err == nil { - t.Errorf("typeForName(%q) = _, %v, want _, ", test, err) - } - } -} - -func (x) TestFileDescContainingExtension(t *testing.T) { - for _, test := range []struct { - st reflect.Type - extNum int32 - want *dpb.FileDescriptorProto - }{ - {reflect.TypeOf(pb.ToBeExtended{}), 13, fdProto2Ext}, - {reflect.TypeOf(pb.ToBeExtended{}), 17, fdProto2Ext}, - {reflect.TypeOf(pb.ToBeExtended{}), 19, fdProto2Ext}, - {reflect.TypeOf(pb.ToBeExtended{}), 23, fdProto2Ext2}, - {reflect.TypeOf(pb.ToBeExtended{}), 29, fdProto2Ext2}, - } { - fd, err := fileDescContainingExtension(test.st, test.extNum) - if err != nil || !proto.Equal(fd, test.want) { - t.Errorf("fileDescContainingExtension(%q) = %q, %v, want %q, ", test.st, fd, err, test.want) - } - } -} - -// intArray is used to sort []int32 -type intArray []int32 - -func (s intArray) Len() int { return len(s) } -func (s intArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s intArray) Less(i, j int) bool { return s[i] < s[j] } - -func (x) TestAllExtensionNumbersForType(t *testing.T) { - for _, test := range []struct { - st reflect.Type - want []int32 - }{ - {reflect.TypeOf(pb.ToBeExtended{}), []int32{13, 17, 19, 23, 29}}, - } { - r, err := s.allExtensionNumbersForType(test.st) - sort.Sort(intArray(r)) - if err != nil || !reflect.DeepEqual(r, test.want) { - t.Errorf("allExtensionNumbersForType(%q) = %v, %v, want %v, ", test.st, r, err, test.want) - } - } -} - -// Do end2end tests. - -type server struct { - pb.UnimplementedSearchServiceServer -} - -func (s *server) Search(ctx context.Context, in *pb.SearchRequest) (*pb.SearchResponse, error) { - return &pb.SearchResponse{}, nil -} - -func (s *server) StreamingSearch(stream pb.SearchService_StreamingSearchServer) error { - return nil -} - -type serverV3 struct{} - -func (s *serverV3) Search(ctx context.Context, in *pbv3.SearchRequestV3) (*pbv3.SearchResponseV3, error) { - return &pbv3.SearchResponseV3{}, nil -} - -func (s *serverV3) StreamingSearch(stream pbv3.SearchServiceV3_StreamingSearchServer) error { - return nil -} - -func (x) TestReflectionEnd2end(t *testing.T) { - // Start server. - lis, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatalf("failed to listen: %v", err) - } - s := grpc.NewServer() - pb.RegisterSearchServiceServer(s, &server{}) - pbv3.RegisterSearchServiceV3Server(s, &serverV3{}) - // Register reflection service on s. - Register(s) - go s.Serve(lis) - - // Create client. - conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) - if err != nil { - t.Fatalf("cannot connect to server: %v", err) - } - defer conn.Close() - - c := rpb.NewServerReflectionClient(conn) - stream, err := c.ServerReflectionInfo(context.Background(), grpc.WaitForReady(true)) - if err != nil { - t.Fatalf("cannot get ServerReflectionInfo: %v", err) - } - - testFileByFilenameTransitiveClosure(t, stream, true) - testFileByFilenameTransitiveClosure(t, stream, false) - testFileByFilename(t, stream) - testFileByFilenameError(t, stream) - testFileContainingSymbol(t, stream) - testFileContainingSymbolError(t, stream) - testFileContainingExtension(t, stream) - testFileContainingExtensionError(t, stream) - testAllExtensionNumbersOfType(t, stream) - testAllExtensionNumbersOfTypeError(t, stream) - testListServices(t, stream) - - s.Stop() -} - -func testFileByFilenameTransitiveClosure(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient, expectClosure bool) { - filename := "reflection/grpc_testing/proto2_ext2.proto" - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_FileByFilename{ - FileByFilename: filename, - }, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_FileDescriptorResponse: - if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[0], fdProto2Ext2Byte) { - t.Errorf("FileByFilename(%v)\nreceived: %q,\nwant: %q", filename, r.GetFileDescriptorResponse().FileDescriptorProto[0], fdProto2Ext2Byte) - } - if expectClosure { - if len(r.GetFileDescriptorResponse().FileDescriptorProto) != 2 { - t.Errorf("FileByFilename(%v) returned %v file descriptors, expected 2", filename, len(r.GetFileDescriptorResponse().FileDescriptorProto)) - } else if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[1], fdProto2Byte) { - t.Errorf("FileByFilename(%v)\nreceived: %q,\nwant: %q", filename, r.GetFileDescriptorResponse().FileDescriptorProto[1], fdProto2Byte) - } - } else if len(r.GetFileDescriptorResponse().FileDescriptorProto) != 1 { - t.Errorf("FileByFilename(%v) returned %v file descriptors, expected 1", filename, len(r.GetFileDescriptorResponse().FileDescriptorProto)) - } - default: - t.Errorf("FileByFilename(%v) = %v, want type ", filename, r.MessageResponse) - } -} - -func testFileByFilename(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { - for _, test := range []struct { - filename string - want []byte - }{ - {"reflection/grpc_testing/test.proto", fdTestByte}, - {"reflection/grpc_testing/proto2.proto", fdProto2Byte}, - {"reflection/grpc_testing/proto2_ext.proto", fdProto2ExtByte}, - } { - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_FileByFilename{ - FileByFilename: test.filename, - }, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_FileDescriptorResponse: - if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) { - t.Errorf("FileByFilename(%v)\nreceived: %q,\nwant: %q", test.filename, r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) - } - default: - t.Errorf("FileByFilename(%v) = %v, want type ", test.filename, r.MessageResponse) - } - } -} - -func testFileByFilenameError(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { - for _, test := range []string{ - "test.poto", - "proo2.proto", - "proto2_et.proto", - } { - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_FileByFilename{ - FileByFilename: test, - }, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_ErrorResponse: - default: - t.Errorf("FileByFilename(%v) = %v, want type ", test, r.MessageResponse) - } - } -} - -func testFileContainingSymbol(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { - for _, test := range []struct { - symbol string - want []byte - }{ - {"grpc.testing.SearchService", fdTestByte}, - {"grpc.testing.SearchService.Search", fdTestByte}, - {"grpc.testing.SearchService.StreamingSearch", fdTestByte}, - {"grpc.testing.SearchResponse", fdTestByte}, - {"grpc.testing.ToBeExtended", fdProto2Byte}, - // Test support package v3. - {"grpc.testingv3.SearchServiceV3", fdTestv3Byte}, - {"grpc.testingv3.SearchServiceV3.Search", fdTestv3Byte}, - {"grpc.testingv3.SearchServiceV3.StreamingSearch", fdTestv3Byte}, - {"grpc.testingv3.SearchResponseV3", fdTestv3Byte}, - // search for field, oneof, enum, and enum value symbols, too - {"grpc.testingv3.SearchResponseV3.Result.snippets", fdTestv3Byte}, - {"grpc.testingv3.SearchResponseV3.Result.Value.val", fdTestv3Byte}, - {"grpc.testingv3.SearchResponseV3.Result.Value.str", fdTestv3Byte}, - {"grpc.testingv3.SearchResponseV3.State", fdTestv3Byte}, - {"grpc.testingv3.SearchResponseV3.State.FRESH", fdTestv3Byte}, - } { - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_FileContainingSymbol{ - FileContainingSymbol: test.symbol, - }, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_FileDescriptorResponse: - if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) { - t.Errorf("FileContainingSymbol(%v)\nreceived: %q,\nwant: %q", test.symbol, r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) - } - default: - t.Errorf("FileContainingSymbol(%v) = %v, want type ", test.symbol, r.MessageResponse) - } - } -} - -func testFileContainingSymbolError(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { - for _, test := range []string{ - "grpc.testing.SerchService", - "grpc.testing.SearchService.SearchE", - "grpc.tesing.SearchResponse", - "gpc.testing.ToBeExtended", - } { - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_FileContainingSymbol{ - FileContainingSymbol: test, - }, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_ErrorResponse: - default: - t.Errorf("FileContainingSymbol(%v) = %v, want type ", test, r.MessageResponse) - } - } -} - -func testFileContainingExtension(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { - for _, test := range []struct { - typeName string - extNum int32 - want []byte - }{ - {"grpc.testing.ToBeExtended", 13, fdProto2ExtByte}, - {"grpc.testing.ToBeExtended", 17, fdProto2ExtByte}, - {"grpc.testing.ToBeExtended", 19, fdProto2ExtByte}, - {"grpc.testing.ToBeExtended", 23, fdProto2Ext2Byte}, - {"grpc.testing.ToBeExtended", 29, fdProto2Ext2Byte}, - } { - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_FileContainingExtension{ - FileContainingExtension: &rpb.ExtensionRequest{ - ContainingType: test.typeName, - ExtensionNumber: test.extNum, - }, - }, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_FileDescriptorResponse: - if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) { - t.Errorf("FileContainingExtension(%v, %v)\nreceived: %q,\nwant: %q", test.typeName, test.extNum, r.GetFileDescriptorResponse().FileDescriptorProto[0], test.want) - } - default: - t.Errorf("FileContainingExtension(%v, %v) = %v, want type ", test.typeName, test.extNum, r.MessageResponse) - } - } -} - -func testFileContainingExtensionError(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { - for _, test := range []struct { - typeName string - extNum int32 - }{ - {"grpc.testing.ToBExtended", 17}, - {"grpc.testing.ToBeExtended", 15}, - } { - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_FileContainingExtension{ - FileContainingExtension: &rpb.ExtensionRequest{ - ContainingType: test.typeName, - ExtensionNumber: test.extNum, - }, - }, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_ErrorResponse: - default: - t.Errorf("FileContainingExtension(%v, %v) = %v, want type ", test.typeName, test.extNum, r.MessageResponse) - } - } -} - -func testAllExtensionNumbersOfType(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { - for _, test := range []struct { - typeName string - want []int32 - }{ - {"grpc.testing.ToBeExtended", []int32{13, 17, 19, 23, 29}}, - } { - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_AllExtensionNumbersOfType{ - AllExtensionNumbersOfType: test.typeName, - }, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_AllExtensionNumbersResponse: - extNum := r.GetAllExtensionNumbersResponse().ExtensionNumber - sort.Sort(intArray(extNum)) - if r.GetAllExtensionNumbersResponse().BaseTypeName != test.typeName || - !reflect.DeepEqual(extNum, test.want) { - t.Errorf("AllExtensionNumbersOfType(%v)\nreceived: %v,\nwant: {%q %v}", r.GetAllExtensionNumbersResponse(), test.typeName, test.typeName, test.want) - } - default: - t.Errorf("AllExtensionNumbersOfType(%v) = %v, want type ", test.typeName, r.MessageResponse) - } - } -} - -func testAllExtensionNumbersOfTypeError(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { - for _, test := range []string{ - "grpc.testing.ToBeExtendedE", - } { - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_AllExtensionNumbersOfType{ - AllExtensionNumbersOfType: test, - }, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_ErrorResponse: - default: - t.Errorf("AllExtensionNumbersOfType(%v) = %v, want type ", test, r.MessageResponse) - } - } -} - -func testListServices(t *testing.T, stream rpb.ServerReflection_ServerReflectionInfoClient) { - if err := stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_ListServices{}, - }); err != nil { - t.Fatalf("failed to send request: %v", err) - } - r, err := stream.Recv() - if err != nil { - // io.EOF is not ok. - t.Fatalf("failed to recv response: %v", err) - } - - switch r.MessageResponse.(type) { - case *rpb.ServerReflectionResponse_ListServicesResponse: - services := r.GetListServicesResponse().Service - want := []string{ - "grpc.testingv3.SearchServiceV3", - "grpc.testing.SearchService", - "grpc.reflection.v1alpha.ServerReflection", - } - // Compare service names in response with want. - if len(services) != len(want) { - t.Errorf("= %v, want service names: %v", services, want) - } - m := make(map[string]int) - for _, e := range services { - m[e.Name]++ - } - for _, e := range want { - if m[e] > 0 { - m[e]-- - continue - } - t.Errorf("ListService\nreceived: %v,\nwant: %q", services, want) - } - default: - t.Errorf("ListServices = %v, want type ", r.MessageResponse) - } -} -*/ diff --git a/server/grpc/server_test.go b/server/grpc/server_test.go index 6c9752741a75..d09ab5c5e56c 100644 --- a/server/grpc/server_test.go +++ b/server/grpc/server_test.go @@ -99,18 +99,29 @@ func (s *IntegrationTestSuite) TestGRPCServer_Reflection() { reflectClient := rpb.NewServerReflectionClient(s.conn) stream, err := reflectClient.ServerReflectionInfo(context.Background(), grpc.WaitForReady(true)) s.Require().NoError(err) + defer stream.CloseSend() + s.Require().NoError(stream.Send(&rpb.ServerReflectionRequest{ MessageRequest: &rpb.ServerReflectionRequest_ListServices{}, })) res, err := stream.Recv() s.Require().NoError(err) services := res.GetListServicesResponse().Service - servicesMap := make(map[string]bool) - for _, s := range services { - servicesMap[s.Name] = true + s.Require().Greater(len(services), 0) + + for _, svc := range services { + // make sure every service is resolvable + s.Require().NoError(stream.Send(&rpb.ServerReflectionRequest{ + MessageRequest: &rpb.ServerReflectionRequest_FileContainingSymbol{ + FileContainingSymbol: svc.Name, + }, + })) + + res, err = stream.Recv() + s.Require().NoError(err) + + s.Require().Nil(res.GetErrorResponse(), "error", res.GetErrorResponse()) } - // Make sure the following services are present - s.Require().True(servicesMap["cosmos.bank.v1beta1.Query"]) } func (s *IntegrationTestSuite) TestGRPCServer_GetTxsEvent() { From 034b0d89128e6bb42826ee6f60d04f9d09989583 Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja Date: Fri, 19 Mar 2021 16:45:40 +0100 Subject: [PATCH 3/9] fix: make tests resolve imports in a transitive way --- go.mod | 3 ++- go.sum | 11 +++++++++++ server/grpc/server_test.go | 36 ++++++++++++++++-------------------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 6f88f451cd5b..16fb81b220f3 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/hashicorp/golang-lru v0.5.4 github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 github.com/improbable-eng/grpc-web v0.14.0 + github.com/jhump/protoreflect v1.8.2 github.com/magiconair/properties v1.8.4 github.com/mattn/go-isatty v0.0.12 github.com/otiai10/copy v1.5.0 @@ -53,7 +54,7 @@ require ( golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f google.golang.org/grpc v1.36.0 - google.golang.org/protobuf v1.25.0 + google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12 gopkg.in/ini.v1 v1.61.0 // indirect gopkg.in/yaml.v2 v2.4.0 nhooyr.io/websocket v1.8.6 // indirect diff --git a/go.sum b/go.sum index b8d2468d1509..644279fa00fa 100644 --- a/go.sum +++ b/go.sum @@ -289,6 +289,7 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= @@ -368,6 +369,8 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.8.2 h1:k2xE7wcUomeqwY0LDCYA16y4WWfyTcMx5mKhk0d4ua0= +github.com/jhump/protoreflect v1.8.2/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= @@ -472,6 +475,7 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -697,6 +701,7 @@ github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+m github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= @@ -884,10 +889,13 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -937,6 +945,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12 h1:OwhZOOMuf7leLaSCuxtQ9FW7ui2L2L6UKOtKAUqovUQ= +google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -977,6 +987,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/server/grpc/server_test.go b/server/grpc/server_test.go index d09ab5c5e56c..23314facc7d8 100644 --- a/server/grpc/server_test.go +++ b/server/grpc/server_test.go @@ -6,6 +6,9 @@ import ( "context" "fmt" "testing" + "time" + + "github.com/jhump/protoreflect/grpcreflect" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -96,31 +99,24 @@ func (s *IntegrationTestSuite) TestGRPCServer_BankBalance() { func (s *IntegrationTestSuite) TestGRPCServer_Reflection() { // Test server reflection - reflectClient := rpb.NewServerReflectionClient(s.conn) - stream, err := reflectClient.ServerReflectionInfo(context.Background(), grpc.WaitForReady(true)) - s.Require().NoError(err) - defer stream.CloseSend() - - s.Require().NoError(stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_ListServices{}, - })) - res, err := stream.Recv() + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + stub := rpb.NewServerReflectionClient(s.conn) + // NOTE(fdymylja): we use grpcreflect because it solves imports too + // so that we can always assert that given a reflection server it is + // possible to fully query all the methods, without having any context + // on the proto registry + rc := grpcreflect.NewClient(ctx, stub) + + services, err := rc.ListServices() s.Require().NoError(err) - services := res.GetListServicesResponse().Service s.Require().Greater(len(services), 0) for _, svc := range services { - // make sure every service is resolvable - s.Require().NoError(stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_FileContainingSymbol{ - FileContainingSymbol: svc.Name, - }, - })) - - res, err = stream.Recv() + file, err := rc.FileContainingSymbol(svc) s.Require().NoError(err) - - s.Require().Nil(res.GetErrorResponse(), "error", res.GetErrorResponse()) + sd := file.FindSymbol(svc) + s.Require().NotNil(sd) } } From cb219124c14feea9155d596e7854608bf7e650f7 Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja Date: Fri, 19 Mar 2021 16:50:08 +0100 Subject: [PATCH 4/9] chore: cleanup getMessageType --- server/grpc/gogoreflection/fix_registration.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/server/grpc/gogoreflection/fix_registration.go b/server/grpc/gogoreflection/fix_registration.go index 0dfa0d7d73b7..3f7c8b8fa53e 100644 --- a/server/grpc/gogoreflection/fix_registration.go +++ b/server/grpc/gogoreflection/fix_registration.go @@ -4,7 +4,6 @@ import ( "bytes" "compress/gzip" "fmt" - "log" "reflect" _ "github.com/gogo/protobuf/gogoproto" // required so it does register the gogoproto file descriptor @@ -87,10 +86,9 @@ func getFileDescriptor(filePath string) []byte { } func getMessageType(name string) reflect.Type { - log.Printf("asking for type: %s", name) typ := gogoproto.MessageType(name) - if typ == nil { - log.Printf("failed type: %s", name) + if typ != nil { + return typ } - return typ + return proto.MessageType(name) } From 79d481ec9945a12a65cadff24d709ab82b31b439 Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja Date: Mon, 22 Mar 2021 10:39:22 +0100 Subject: [PATCH 5/9] chore: lint --- server/grpc/gogoreflection/fix_registration.go | 6 ++++++ server/grpc/gogoreflection/serverreflection.go | 1 + 2 files changed, 7 insertions(+) diff --git a/server/grpc/gogoreflection/fix_registration.go b/server/grpc/gogoreflection/fix_registration.go index 3f7c8b8fa53e..05a8bca7364a 100644 --- a/server/grpc/gogoreflection/fix_registration.go +++ b/server/grpc/gogoreflection/fix_registration.go @@ -8,6 +8,8 @@ import ( _ "github.com/gogo/protobuf/gogoproto" // required so it does register the gogoproto file descriptor gogoproto "github.com/gogo/protobuf/proto" + + // nolint: staticcheck "github.com/golang/protobuf/proto" dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" _ "github.com/regen-network/cosmos-proto" // look above @@ -57,6 +59,8 @@ func init() { } } +// compress compresses the given file descriptor +// nolint: interfacer func compress(fd *dpb.FileDescriptorProto) ([]byte, error) { fdBytes, err := proto.Marshal(fd) if err != nil { @@ -82,6 +86,7 @@ func getFileDescriptor(filePath string) []byte { if len(fd) != 0 { return fd } + // nolint: staticcheck return proto.FileDescriptor(filePath) } @@ -90,5 +95,6 @@ func getMessageType(name string) reflect.Type { if typ != nil { return typ } + // nolint: staticcheck return proto.MessageType(name) } diff --git a/server/grpc/gogoreflection/serverreflection.go b/server/grpc/gogoreflection/serverreflection.go index 1a08fdd91f80..f19d0e5eefd0 100644 --- a/server/grpc/gogoreflection/serverreflection.go +++ b/server/grpc/gogoreflection/serverreflection.go @@ -48,6 +48,7 @@ import ( "sync" gogoproto "github.com/gogo/protobuf/proto" + // nolint: staticcheck "github.com/golang/protobuf/proto" dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" "google.golang.org/grpc" From 65674915d4957e039e560ab600811f892da2a2f3 Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja Date: Mon, 22 Mar 2021 13:33:25 +0100 Subject: [PATCH 6/9] add: extensions reflection --- .../grpc/gogoreflection/fix_registration.go | 43 +++++++++++++++++++ .../grpc/gogoreflection/serverreflection.go | 15 +------ 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/server/grpc/gogoreflection/fix_registration.go b/server/grpc/gogoreflection/fix_registration.go index 05a8bca7364a..51fef99dcae2 100644 --- a/server/grpc/gogoreflection/fix_registration.go +++ b/server/grpc/gogoreflection/fix_registration.go @@ -98,3 +98,46 @@ func getMessageType(name string) reflect.Type { // nolint: staticcheck return proto.MessageType(name) } + +func getExtension(extID int32, m proto.Message) *gogoproto.ExtensionDesc { + // check first in gogoproto registry + for id, desc := range gogoproto.RegisteredExtensions(m) { + if id == extID { + return desc + } + } + // check into proto registry + // nolint: staticcheck + for id, desc := range proto.RegisteredExtensions(m) { + if id == extID { + return &gogoproto.ExtensionDesc{ + ExtendedType: desc.ExtendedType, + ExtensionType: desc.ExtensionType, + Field: desc.Field, + Name: desc.Name, + Tag: desc.Tag, + Filename: desc.Filename, + } + } + } + + return nil +} + +func getExtensionsNumbers(m proto.Message) []int32 { + gogoProtoExts := gogoproto.RegisteredExtensions(m) + out := make([]int32, 0, len(gogoProtoExts)) + for id := range gogoProtoExts { + out = append(out, id) + } + if len(out) != 0 { + return out + } + // nolint: staticcheck + protoExts := proto.RegisteredExtensions(m) + out = make([]int32, 0, len(protoExts)) + for id := range protoExts { + out = append(out, id) + } + return out +} diff --git a/server/grpc/gogoreflection/serverreflection.go b/server/grpc/gogoreflection/serverreflection.go index f19d0e5eefd0..c2a0828e3bc2 100644 --- a/server/grpc/gogoreflection/serverreflection.go +++ b/server/grpc/gogoreflection/serverreflection.go @@ -47,7 +47,6 @@ import ( "sort" "sync" - gogoproto "github.com/gogo/protobuf/proto" // nolint: staticcheck "github.com/golang/protobuf/proto" dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" @@ -243,13 +242,7 @@ func fileDescContainingExtension(st reflect.Type, ext int32) (*dpb.FileDescripto return nil, fmt.Errorf("failed to create message from type: %v", st) } - var extDesc *gogoproto.ExtensionDesc - for id, desc := range gogoproto.RegisteredExtensions(m) { - if id == ext { - extDesc = desc - break - } - } + extDesc := getExtension(ext, m) if extDesc == nil { return nil, fmt.Errorf("failed to find registered extension for extension number %v", ext) @@ -264,11 +257,7 @@ func (s *serverReflectionServer) allExtensionNumbersForType(st reflect.Type) ([] return nil, fmt.Errorf("failed to create message from type: %v", st) } - exts := gogoproto.RegisteredExtensions(m) - out := make([]int32, 0, len(exts)) - for id := range exts { - out = append(out, id) - } + out := getExtensionsNumbers(m) return out, nil } From 716a145b9b546edf3f451af07aab758cef826fb3 Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja Date: Mon, 22 Mar 2021 13:42:56 +0100 Subject: [PATCH 7/9] chore: update interact-node.md docs --- docs/run-node/interact-node.md | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index 9b7fa11800d0..7c29170ec644 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -60,7 +60,7 @@ Since the code generation library largely depends on your own tech stack, we wil ### grpcurl -[grpcurl])https://github.com/fullstorydev/grpcurl is like `curl` but for gRPC. It is also available as a Go library, but we will use it only as a CLI command for debugging and testing purposes. Follow the instructions in the previous link to install it. +[grpcurl](https://github.com/fullstorydev/grpcurl) is like `curl` but for gRPC. It is also available as a Go library, but we will use it only as a CLI command for debugging and testing purposes. Follow the instructions in the previous link to install it. Assuming you have a local node running (either a localnet, or connected a live network), you should be able to run the following command to list the Protobuf services available (you can replace `localhost:9000` by the gRPC server endpoint of another node, which is configured under the `grpc.address` field inside [`app.toml`](../run-node/run-node.md#configuring-the-node-using-apptoml)): @@ -70,27 +70,19 @@ grpcurl -plaintext localhost:9090 list You should see a list of gRPC services, like `cosmos.bank.v1beta1.Query`. This is called reflection, which is a Protobuf endpoint returning a description of all available endpoints. Each of these represents a different Protobuf service, and each service exposes multiple RPC methods you can query against. -In the Cosmos SDK, we use [gogoprotobuf](https://github.com/gogo/protobuf) for code generation, and [grpc-go](https://github.com/grpc/grpc-go) for creating the gRPC server. Unfortunately, these two don't play well together, and more in-depth reflection (such as using grpcurl's `describe`) is not possible. See [this issue](https://github.com/grpc/grpc-go/issues/1873) for more info. - -Instead, we need to manually pass the reference to relevant `.proto` files. For example: +In order to get a description of the service you can run the following command: ```bash grpcurl \ - -import-path ./proto \ # Import these proto files too - -import-path ./third_party/proto \ # Import these proto files too - -proto ./proto/cosmos/bank/v1beta1/query.proto \ # That's the proto file with the description of your service localhost:9090 \ describe cosmos.bank.v1beta1.Query # Service we want to inspect ``` -Once the Protobuf definitions are given, making a gRPC query is then straightforward, by calling the correct `Query` service RPC method, and by passing the request argument as data (`-d` flag): +It's also possible to execute an RPC call to query the node for information: ```bash grpcurl \ -plaintext - -import-path ./proto \ - -import-path ./third_party/proto \ - -proto ./proto/cosmos/bank/v1beta1/query.proto \ -d '{"address":"$MY_VALIDATOR"}' \ localhost:9090 \ cosmos.bank.v1beta1.Query/AllBalances @@ -104,10 +96,7 @@ You may also query for historical data by passing some [gRPC metadata](https://g ```bash grpcurl \ - -plaintext - -import-path ./proto \ - -import-path ./third_party/proto \ - -proto ./proto/cosmos/bank/v1beta1/query.proto \ + -plaintext \ -H "x-cosmos-block-height: 279256" \ -d '{"address":"$MY_VALIDATOR"}' \ localhost:9090 \ From b7c26e46da7139e08aff09ab882c6a01ce6ae279 Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja Date: Mon, 22 Mar 2021 15:30:44 +0100 Subject: [PATCH 8/9] chore: update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dda608c263ac..4d2020c9cfa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +* (gRPC) [\#8945](https://github.com/cosmos/cosmos-sdk/pull/8945) gRPC reflection now works correctly. * (keyring) [#\8635](https://github.com/cosmos/cosmos-sdk/issues/8635) Remove hardcoded default passphrase value on `NewMnemonic` * (x/bank) [\#8434](https://github.com/cosmos/cosmos-sdk/pull/8434) Fix legacy REST API `GET /bank/total` and `GET /bank/total/{denom}` in swagger * (x/slashing) [\#8427](https://github.com/cosmos/cosmos-sdk/pull/8427) Fix query signing infos command From def738ba6c229e1cbe2e1e16af962d01bf07e36b Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja <33157909+fdymylja@users.noreply.github.com> Date: Mon, 22 Mar 2021 19:59:23 +0100 Subject: [PATCH 9/9] Update server/grpc/gogoreflection/fix_registration.go Co-authored-by: Robert Zaremba --- server/grpc/gogoreflection/fix_registration.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/grpc/gogoreflection/fix_registration.go b/server/grpc/gogoreflection/fix_registration.go index 51fef99dcae2..ab7750574845 100644 --- a/server/grpc/gogoreflection/fix_registration.go +++ b/server/grpc/gogoreflection/fix_registration.go @@ -28,7 +28,7 @@ var importsToFix = map[string]string{ func fixRegistration(registeredAs, importedAs string) error { raw := gogoproto.FileDescriptor(registeredAs) if len(raw) == 0 { - return fmt.Errorf("file descriptor not found: %s", registeredAs) + return fmt.Errorf("file descriptor not found for %s", registeredAs) } fd, err := decodeFileDesc(raw)