From 642dd63a85275a96d172f446911fd04111e2c74c Mon Sep 17 00:00:00 2001 From: Joshua Humphries <2035234+jhump@users.noreply.github.com> Date: Mon, 12 Jun 2023 17:21:44 -0400 Subject: [PATCH] reflection: expose both v1 and v1alpha reflection services (#6329) --- reflection/adapt.go | 187 ++++++++++++++++++++++ reflection/serverreflection.go | 89 +++++++---- reflection/serverreflection_test.go | 235 ++++++++++++++++++++-------- 3 files changed, 411 insertions(+), 100 deletions(-) create mode 100644 reflection/adapt.go diff --git a/reflection/adapt.go b/reflection/adapt.go new file mode 100644 index 000000000000..fa5aad500b6e --- /dev/null +++ b/reflection/adapt.go @@ -0,0 +1,187 @@ +/* + * + * Copyright 2023 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 + +import ( + v1grpc "google.golang.org/grpc/reflection/grpc_reflection_v1" + v1pb "google.golang.org/grpc/reflection/grpc_reflection_v1" + v1alphagrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" + v1alphapb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" +) + +// asV1Alpha returns an implementation of the v1alpha version of the reflection +// interface that delegates all calls to the given v1 version. +func asV1Alpha(svr v1grpc.ServerReflectionServer) v1alphagrpc.ServerReflectionServer { + return v1AlphaServerImpl{svr: svr} +} + +type v1AlphaServerImpl struct { + svr v1grpc.ServerReflectionServer +} + +func (s v1AlphaServerImpl) ServerReflectionInfo(stream v1alphagrpc.ServerReflection_ServerReflectionInfoServer) error { + return s.svr.ServerReflectionInfo(v1AlphaServerStreamAdapter{stream}) +} + +type v1AlphaServerStreamAdapter struct { + v1alphagrpc.ServerReflection_ServerReflectionInfoServer +} + +func (s v1AlphaServerStreamAdapter) Send(response *v1pb.ServerReflectionResponse) error { + return s.ServerReflection_ServerReflectionInfoServer.Send(v1ToV1AlphaResponse(response)) +} + +func (s v1AlphaServerStreamAdapter) Recv() (*v1pb.ServerReflectionRequest, error) { + resp, err := s.ServerReflection_ServerReflectionInfoServer.Recv() + if err != nil { + return nil, err + } + return v1AlphaToV1Request(resp), nil +} + +func v1ToV1AlphaResponse(v1 *v1pb.ServerReflectionResponse) *v1alphapb.ServerReflectionResponse { + var v1alpha v1alphapb.ServerReflectionResponse + v1alpha.ValidHost = v1.ValidHost + if v1.OriginalRequest != nil { + v1alpha.OriginalRequest = v1ToV1AlphaRequest(v1.OriginalRequest) + } + switch mr := v1.MessageResponse.(type) { + case *v1pb.ServerReflectionResponse_FileDescriptorResponse: + if mr != nil { + v1alpha.MessageResponse = &v1alphapb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &v1alphapb.FileDescriptorResponse{ + FileDescriptorProto: mr.FileDescriptorResponse.GetFileDescriptorProto(), + }, + } + } + case *v1pb.ServerReflectionResponse_AllExtensionNumbersResponse: + if mr != nil { + v1alpha.MessageResponse = &v1alphapb.ServerReflectionResponse_AllExtensionNumbersResponse{ + AllExtensionNumbersResponse: &v1alphapb.ExtensionNumberResponse{ + BaseTypeName: mr.AllExtensionNumbersResponse.GetBaseTypeName(), + ExtensionNumber: mr.AllExtensionNumbersResponse.GetExtensionNumber(), + }, + } + } + case *v1pb.ServerReflectionResponse_ListServicesResponse: + if mr != nil { + svcs := make([]*v1alphapb.ServiceResponse, len(mr.ListServicesResponse.GetService())) + for i, svc := range mr.ListServicesResponse.GetService() { + svcs[i] = &v1alphapb.ServiceResponse{ + Name: svc.GetName(), + } + } + v1alpha.MessageResponse = &v1alphapb.ServerReflectionResponse_ListServicesResponse{ + ListServicesResponse: &v1alphapb.ListServiceResponse{ + Service: svcs, + }, + } + } + case *v1pb.ServerReflectionResponse_ErrorResponse: + if mr != nil { + v1alpha.MessageResponse = &v1alphapb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1alphapb.ErrorResponse{ + ErrorCode: mr.ErrorResponse.GetErrorCode(), + ErrorMessage: mr.ErrorResponse.GetErrorMessage(), + }, + } + } + default: + // no value set + } + return &v1alpha +} + +func v1AlphaToV1Request(v1alpha *v1alphapb.ServerReflectionRequest) *v1pb.ServerReflectionRequest { + var v1 v1pb.ServerReflectionRequest + v1.Host = v1alpha.Host + switch mr := v1alpha.MessageRequest.(type) { + case *v1alphapb.ServerReflectionRequest_FileByFilename: + v1.MessageRequest = &v1pb.ServerReflectionRequest_FileByFilename{ + FileByFilename: mr.FileByFilename, + } + case *v1alphapb.ServerReflectionRequest_FileContainingSymbol: + v1.MessageRequest = &v1pb.ServerReflectionRequest_FileContainingSymbol{ + FileContainingSymbol: mr.FileContainingSymbol, + } + case *v1alphapb.ServerReflectionRequest_FileContainingExtension: + if mr.FileContainingExtension != nil { + v1.MessageRequest = &v1pb.ServerReflectionRequest_FileContainingExtension{ + FileContainingExtension: &v1pb.ExtensionRequest{ + ContainingType: mr.FileContainingExtension.GetContainingType(), + ExtensionNumber: mr.FileContainingExtension.GetExtensionNumber(), + }, + } + } + case *v1alphapb.ServerReflectionRequest_AllExtensionNumbersOfType: + v1.MessageRequest = &v1pb.ServerReflectionRequest_AllExtensionNumbersOfType{ + AllExtensionNumbersOfType: mr.AllExtensionNumbersOfType, + } + case *v1alphapb.ServerReflectionRequest_ListServices: + v1.MessageRequest = &v1pb.ServerReflectionRequest_ListServices{ + ListServices: mr.ListServices, + } + default: + // no value set + } + return &v1 +} + +func v1ToV1AlphaRequest(v1 *v1pb.ServerReflectionRequest) *v1alphapb.ServerReflectionRequest { + var v1alpha v1alphapb.ServerReflectionRequest + v1alpha.Host = v1.Host + switch mr := v1.MessageRequest.(type) { + case *v1pb.ServerReflectionRequest_FileByFilename: + if mr != nil { + v1alpha.MessageRequest = &v1alphapb.ServerReflectionRequest_FileByFilename{ + FileByFilename: mr.FileByFilename, + } + } + case *v1pb.ServerReflectionRequest_FileContainingSymbol: + if mr != nil { + v1alpha.MessageRequest = &v1alphapb.ServerReflectionRequest_FileContainingSymbol{ + FileContainingSymbol: mr.FileContainingSymbol, + } + } + case *v1pb.ServerReflectionRequest_FileContainingExtension: + if mr != nil { + v1alpha.MessageRequest = &v1alphapb.ServerReflectionRequest_FileContainingExtension{ + FileContainingExtension: &v1alphapb.ExtensionRequest{ + ContainingType: mr.FileContainingExtension.GetContainingType(), + ExtensionNumber: mr.FileContainingExtension.GetExtensionNumber(), + }, + } + } + case *v1pb.ServerReflectionRequest_AllExtensionNumbersOfType: + if mr != nil { + v1alpha.MessageRequest = &v1alphapb.ServerReflectionRequest_AllExtensionNumbersOfType{ + AllExtensionNumbersOfType: mr.AllExtensionNumbersOfType, + } + } + case *v1pb.ServerReflectionRequest_ListServices: + if mr != nil { + v1alpha.MessageRequest = &v1alphapb.ServerReflectionRequest_ListServices{ + ListServices: mr.ListServices, + } + } + default: + // no value set + } + return &v1alpha +} diff --git a/reflection/serverreflection.go b/reflection/serverreflection.go index e2f9ebfbbce8..a70295bcaa7d 100644 --- a/reflection/serverreflection.go +++ b/reflection/serverreflection.go @@ -48,8 +48,9 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" + v1grpc "google.golang.org/grpc/reflection/grpc_reflection_v1" + v1pb "google.golang.org/grpc/reflection/grpc_reflection_v1" v1alphagrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" - v1alphapb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" ) // GRPCServer is the interface provided by a gRPC server. It is implemented by @@ -63,9 +64,19 @@ type GRPCServer interface { var _ GRPCServer = (*grpc.Server)(nil) // Register registers the server reflection service on the given gRPC server. +// Both the v1 and v1alpha versions are registered. func Register(s GRPCServer) { - svr := NewServer(ServerOptions{Services: s}) - v1alphagrpc.RegisterServerReflectionServer(s, svr) + svr := NewServerV1(ServerOptions{Services: s}) + v1alphagrpc.RegisterServerReflectionServer(s, asV1Alpha(svr)) + v1grpc.RegisterServerReflectionServer(s, svr) +} + +// RegisterV1 registers only the v1 version of the server reflection service +// on the given gRPC server. Many clients may only support v1alpha so most +// users should use Register instead, at least until clients have upgraded. +func RegisterV1(s GRPCServer) { + svr := NewServerV1(ServerOptions{Services: s}) + v1grpc.RegisterServerReflectionServer(s, svr) } // ServiceInfoProvider is an interface used to retrieve metadata about the @@ -120,13 +131,27 @@ type ServerOptions struct { // NewServer returns a reflection server implementation using the given options. // This can be used to customize behavior of the reflection service. Most usages -// should prefer to use Register instead. +// should prefer to use Register instead. For backwards compatibility reasons, +// this returns the v1alpha version of the reflection server. For a v1 version +// of the reflection server, see NewServerV1. // // # Experimental // // Notice: This function is EXPERIMENTAL and may be changed or removed in a // later release. func NewServer(opts ServerOptions) v1alphagrpc.ServerReflectionServer { + return asV1Alpha(NewServerV1(opts)) +} + +// NewServerV1 returns a reflection server implementation using the given options. +// This can be used to customize behavior of the reflection service. Most usages +// should prefer to use Register instead. +// +// # Experimental +// +// Notice: This function is EXPERIMENTAL and may be changed or removed in a +// later release. +func NewServerV1(opts ServerOptions) v1grpc.ServerReflectionServer { if opts.DescriptorResolver == nil { opts.DescriptorResolver = protoregistry.GlobalFiles } @@ -215,11 +240,11 @@ func (s *serverReflectionServer) allExtensionNumbersForTypeName(name string) ([] } // listServices returns the names of services this server exposes. -func (s *serverReflectionServer) listServices() []*v1alphapb.ServiceResponse { +func (s *serverReflectionServer) listServices() []*v1pb.ServiceResponse { serviceInfo := s.s.GetServiceInfo() - resp := make([]*v1alphapb.ServiceResponse, 0, len(serviceInfo)) + resp := make([]*v1pb.ServiceResponse, 0, len(serviceInfo)) for svc := range serviceInfo { - resp = append(resp, &v1alphapb.ServiceResponse{Name: svc}) + resp = append(resp, &v1pb.ServiceResponse{Name: svc}) } sort.Slice(resp, func(i, j int) bool { return resp[i].Name < resp[j].Name @@ -228,7 +253,7 @@ func (s *serverReflectionServer) listServices() []*v1alphapb.ServiceResponse { } // ServerReflectionInfo is the reflection service handler. -func (s *serverReflectionServer) ServerReflectionInfo(stream v1alphagrpc.ServerReflection_ServerReflectionInfoServer) error { +func (s *serverReflectionServer) ServerReflectionInfo(stream v1grpc.ServerReflection_ServerReflectionInfoServer) error { sentFileDescriptors := make(map[string]bool) for { in, err := stream.Recv() @@ -239,79 +264,79 @@ func (s *serverReflectionServer) ServerReflectionInfo(stream v1alphagrpc.ServerR return err } - out := &v1alphapb.ServerReflectionResponse{ + out := &v1pb.ServerReflectionResponse{ ValidHost: in.Host, OriginalRequest: in, } switch req := in.MessageRequest.(type) { - case *v1alphapb.ServerReflectionRequest_FileByFilename: + case *v1pb.ServerReflectionRequest_FileByFilename: var b [][]byte fd, err := s.descResolver.FindFileByPath(req.FileByFilename) if err == nil { b, err = s.fileDescWithDependencies(fd, sentFileDescriptors) } if err != nil { - out.MessageResponse = &v1alphapb.ServerReflectionResponse_ErrorResponse{ - ErrorResponse: &v1alphapb.ErrorResponse{ + out.MessageResponse = &v1pb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1pb.ErrorResponse{ ErrorCode: int32(codes.NotFound), ErrorMessage: err.Error(), }, } } else { - out.MessageResponse = &v1alphapb.ServerReflectionResponse_FileDescriptorResponse{ - FileDescriptorResponse: &v1alphapb.FileDescriptorResponse{FileDescriptorProto: b}, + out.MessageResponse = &v1pb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &v1pb.FileDescriptorResponse{FileDescriptorProto: b}, } } - case *v1alphapb.ServerReflectionRequest_FileContainingSymbol: + case *v1pb.ServerReflectionRequest_FileContainingSymbol: b, err := s.fileDescEncodingContainingSymbol(req.FileContainingSymbol, sentFileDescriptors) if err != nil { - out.MessageResponse = &v1alphapb.ServerReflectionResponse_ErrorResponse{ - ErrorResponse: &v1alphapb.ErrorResponse{ + out.MessageResponse = &v1pb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1pb.ErrorResponse{ ErrorCode: int32(codes.NotFound), ErrorMessage: err.Error(), }, } } else { - out.MessageResponse = &v1alphapb.ServerReflectionResponse_FileDescriptorResponse{ - FileDescriptorResponse: &v1alphapb.FileDescriptorResponse{FileDescriptorProto: b}, + out.MessageResponse = &v1pb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &v1pb.FileDescriptorResponse{FileDescriptorProto: b}, } } - case *v1alphapb.ServerReflectionRequest_FileContainingExtension: + case *v1pb.ServerReflectionRequest_FileContainingExtension: typeName := req.FileContainingExtension.ContainingType extNum := req.FileContainingExtension.ExtensionNumber b, err := s.fileDescEncodingContainingExtension(typeName, extNum, sentFileDescriptors) if err != nil { - out.MessageResponse = &v1alphapb.ServerReflectionResponse_ErrorResponse{ - ErrorResponse: &v1alphapb.ErrorResponse{ + out.MessageResponse = &v1pb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1pb.ErrorResponse{ ErrorCode: int32(codes.NotFound), ErrorMessage: err.Error(), }, } } else { - out.MessageResponse = &v1alphapb.ServerReflectionResponse_FileDescriptorResponse{ - FileDescriptorResponse: &v1alphapb.FileDescriptorResponse{FileDescriptorProto: b}, + out.MessageResponse = &v1pb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &v1pb.FileDescriptorResponse{FileDescriptorProto: b}, } } - case *v1alphapb.ServerReflectionRequest_AllExtensionNumbersOfType: + case *v1pb.ServerReflectionRequest_AllExtensionNumbersOfType: extNums, err := s.allExtensionNumbersForTypeName(req.AllExtensionNumbersOfType) if err != nil { - out.MessageResponse = &v1alphapb.ServerReflectionResponse_ErrorResponse{ - ErrorResponse: &v1alphapb.ErrorResponse{ + out.MessageResponse = &v1pb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1pb.ErrorResponse{ ErrorCode: int32(codes.NotFound), ErrorMessage: err.Error(), }, } } else { - out.MessageResponse = &v1alphapb.ServerReflectionResponse_AllExtensionNumbersResponse{ - AllExtensionNumbersResponse: &v1alphapb.ExtensionNumberResponse{ + out.MessageResponse = &v1pb.ServerReflectionResponse_AllExtensionNumbersResponse{ + AllExtensionNumbersResponse: &v1pb.ExtensionNumberResponse{ BaseTypeName: req.AllExtensionNumbersOfType, ExtensionNumber: extNums, }, } } - case *v1alphapb.ServerReflectionRequest_ListServices: - out.MessageResponse = &v1alphapb.ServerReflectionResponse_ListServicesResponse{ - ListServicesResponse: &v1alphapb.ListServiceResponse{ + case *v1pb.ServerReflectionRequest_ListServices: + out.MessageResponse = &v1pb.ServerReflectionResponse_ListServicesResponse{ + ListServicesResponse: &v1pb.ListServiceResponse{ Service: s.listServices(), }, } diff --git a/reflection/serverreflection_test.go b/reflection/serverreflection_test.go index 04e7ba1dbfbd..8a3ca7163f0e 100644 --- a/reflection/serverreflection_test.go +++ b/reflection/serverreflection_test.go @@ -37,6 +37,8 @@ import ( "google.golang.org/protobuf/types/descriptorpb" "google.golang.org/protobuf/types/dynamicpb" + v1grpc "google.golang.org/grpc/reflection/grpc_reflection_v1" + v1pb "google.golang.org/grpc/reflection/grpc_reflection_v1" v1alphagrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" v1alphapb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" pb "google.golang.org/grpc/reflection/grpc_testing" @@ -44,11 +46,8 @@ import ( ) var ( - s = NewServer(ServerOptions{}).(*serverReflectionServer) + s = NewServerV1(ServerOptions{}).(*serverReflectionServer) // fileDescriptor of each test proto file. - fdTest *descriptorpb.FileDescriptorProto - fdTestv3 *descriptorpb.FileDescriptorProto - fdProto2 *descriptorpb.FileDescriptorProto fdProto2Ext *descriptorpb.FileDescriptorProto fdProto2Ext2 *descriptorpb.FileDescriptorProto fdDynamic *descriptorpb.FileDescriptorProto @@ -113,9 +112,9 @@ func loadFileDescDynamic(b []byte) (*descriptorpb.FileDescriptorProto, protorefl } func init() { - fdTest, fdTestByte = loadFileDesc("reflection/grpc_testing/test.proto") - fdTestv3, fdTestv3Byte = loadFileDesc("testv3.proto") - fdProto2, fdProto2Byte = loadFileDesc("reflection/grpc_testing/proto2.proto") + _, fdTestByte = loadFileDesc("reflection/grpc_testing/test.proto") + _, fdTestv3Byte = loadFileDesc("testv3.proto") + _, 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") fdDynamic, fdDynamicFile, fdDynamicByte = loadFileDescDynamic(pbv3.FileDynamicProtoRawDesc) @@ -210,6 +209,7 @@ func (x) TestReflectionEnd2end(t *testing.T) { // Register reflection service on s. Register(s) go s.Serve(lis) + t.Cleanup(s.Stop) // Create client. conn, err := grpc.Dial(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) @@ -218,33 +218,50 @@ func (x) TestReflectionEnd2end(t *testing.T) { } defer conn.Close() - c := v1alphagrpc.NewServerReflectionClient(conn) - ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) - defer cancel() - stream, err := c.ServerReflectionInfo(ctx, grpc.WaitForReady(true)) - if err != nil { - t.Fatalf("cannot get ServerReflectionInfo: %v", err) + clientV1 := v1grpc.NewServerReflectionClient(conn) + clientV1Alpha := v1alphagrpc.NewServerReflectionClient(conn) + testCases := []struct { + name string + client v1grpc.ServerReflectionClient + }{ + { + name: "v1", + client: clientV1, + }, + { + name: "v1alpha", + client: v1AlphaClientAdapter{stub: clientV1Alpha}, + }, } + for _, testCase := range testCases { + c := testCase.client + t.Run(testCase.name, func(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + stream, err := c.ServerReflectionInfo(ctx, 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() + 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) + }) + } } -func testFileByFilenameTransitiveClosure(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient, expectClosure bool) { +func testFileByFilenameTransitiveClosure(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient, expectClosure bool) { filename := "reflection/grpc_testing/proto2_ext2.proto" - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_FileByFilename{ + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_FileByFilename{ FileByFilename: filename, }, }); err != nil { @@ -256,7 +273,7 @@ func testFileByFilenameTransitiveClosure(t *testing.T, stream v1alphagrpc.Server t.Fatalf("failed to recv response: %v", err) } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_FileDescriptorResponse: + case *v1pb.ServerReflectionResponse_FileDescriptorResponse: if !reflect.DeepEqual(r.GetFileDescriptorResponse().FileDescriptorProto[0], fdProto2Ext2Byte) { t.Errorf("FileByFilename(%v)\nreceived: %q,\nwant: %q", filename, r.GetFileDescriptorResponse().FileDescriptorProto[0], fdProto2Ext2Byte) } @@ -274,7 +291,7 @@ func testFileByFilenameTransitiveClosure(t *testing.T, stream v1alphagrpc.Server } } -func testFileByFilename(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient) { +func testFileByFilename(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient) { for _, test := range []struct { filename string want []byte @@ -284,8 +301,8 @@ func testFileByFilename(t *testing.T, stream v1alphagrpc.ServerReflection_Server {"reflection/grpc_testing/proto2_ext.proto", fdProto2ExtByte}, {"dynamic.proto", fdDynamicByte}, } { - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_FileByFilename{ + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_FileByFilename{ FileByFilename: test.filename, }, }); err != nil { @@ -298,7 +315,7 @@ func testFileByFilename(t *testing.T, stream v1alphagrpc.ServerReflection_Server } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_FileDescriptorResponse: + case *v1pb.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) } @@ -308,14 +325,14 @@ func testFileByFilename(t *testing.T, stream v1alphagrpc.ServerReflection_Server } } -func testFileByFilenameError(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient) { +func testFileByFilenameError(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient) { for _, test := range []string{ "test.poto", "proo2.proto", "proto2_et.proto", } { - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_FileByFilename{ + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_FileByFilename{ FileByFilename: test, }, }); err != nil { @@ -328,14 +345,14 @@ func testFileByFilenameError(t *testing.T, stream v1alphagrpc.ServerReflection_S } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_ErrorResponse: + case *v1pb.ServerReflectionResponse_ErrorResponse: default: t.Errorf("FileByFilename(%v) = %v, want type ", test, r.MessageResponse) } } } -func testFileContainingSymbol(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient) { +func testFileContainingSymbol(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient) { for _, test := range []struct { symbol string want []byte @@ -361,8 +378,8 @@ func testFileContainingSymbol(t *testing.T, stream v1alphagrpc.ServerReflection_ {"grpc.testing.DynamicReq", fdDynamicByte}, {"grpc.testing.DynamicRes", fdDynamicByte}, } { - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_FileContainingSymbol{ + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_FileContainingSymbol{ FileContainingSymbol: test.symbol, }, }); err != nil { @@ -375,7 +392,7 @@ func testFileContainingSymbol(t *testing.T, stream v1alphagrpc.ServerReflection_ } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_FileDescriptorResponse: + case *v1pb.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) } @@ -385,15 +402,15 @@ func testFileContainingSymbol(t *testing.T, stream v1alphagrpc.ServerReflection_ } } -func testFileContainingSymbolError(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient) { +func testFileContainingSymbolError(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient) { for _, test := range []string{ "grpc.testing.SerchService", "grpc.testing.SearchService.SearchE", "grpc.tesing.SearchResponse", "gpc.testing.ToBeExtended", } { - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_FileContainingSymbol{ + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_FileContainingSymbol{ FileContainingSymbol: test, }, }); err != nil { @@ -406,14 +423,14 @@ func testFileContainingSymbolError(t *testing.T, stream v1alphagrpc.ServerReflec } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_ErrorResponse: + case *v1pb.ServerReflectionResponse_ErrorResponse: default: t.Errorf("FileContainingSymbol(%v) = %v, want type ", test, r.MessageResponse) } } } -func testFileContainingExtension(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient) { +func testFileContainingExtension(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient) { for _, test := range []struct { typeName string extNum int32 @@ -425,9 +442,9 @@ func testFileContainingExtension(t *testing.T, stream v1alphagrpc.ServerReflecti {"grpc.testing.ToBeExtended", 23, fdProto2Ext2Byte}, {"grpc.testing.ToBeExtended", 29, fdProto2Ext2Byte}, } { - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_FileContainingExtension{ - FileContainingExtension: &v1alphapb.ExtensionRequest{ + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_FileContainingExtension{ + FileContainingExtension: &v1pb.ExtensionRequest{ ContainingType: test.typeName, ExtensionNumber: test.extNum, }, @@ -442,7 +459,7 @@ func testFileContainingExtension(t *testing.T, stream v1alphagrpc.ServerReflecti } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_FileDescriptorResponse: + case *v1pb.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) } @@ -452,7 +469,7 @@ func testFileContainingExtension(t *testing.T, stream v1alphagrpc.ServerReflecti } } -func testFileContainingExtensionError(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient) { +func testFileContainingExtensionError(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient) { for _, test := range []struct { typeName string extNum int32 @@ -460,9 +477,9 @@ func testFileContainingExtensionError(t *testing.T, stream v1alphagrpc.ServerRef {"grpc.testing.ToBExtended", 17}, {"grpc.testing.ToBeExtended", 15}, } { - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_FileContainingExtension{ - FileContainingExtension: &v1alphapb.ExtensionRequest{ + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_FileContainingExtension{ + FileContainingExtension: &v1pb.ExtensionRequest{ ContainingType: test.typeName, ExtensionNumber: test.extNum, }, @@ -477,14 +494,14 @@ func testFileContainingExtensionError(t *testing.T, stream v1alphagrpc.ServerRef } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_ErrorResponse: + case *v1pb.ServerReflectionResponse_ErrorResponse: default: t.Errorf("FileContainingExtension(%v, %v) = %v, want type ", test.typeName, test.extNum, r.MessageResponse) } } } -func testAllExtensionNumbersOfType(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient) { +func testAllExtensionNumbersOfType(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient) { for _, test := range []struct { typeName string want []int32 @@ -492,8 +509,8 @@ func testAllExtensionNumbersOfType(t *testing.T, stream v1alphagrpc.ServerReflec {"grpc.testing.ToBeExtended", []int32{13, 17, 19, 23, 29}}, {"grpc.testing.DynamicReq", nil}, } { - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_AllExtensionNumbersOfType{ + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_AllExtensionNumbersOfType{ AllExtensionNumbersOfType: test.typeName, }, }); err != nil { @@ -506,7 +523,7 @@ func testAllExtensionNumbersOfType(t *testing.T, stream v1alphagrpc.ServerReflec } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_AllExtensionNumbersResponse: + case *v1pb.ServerReflectionResponse_AllExtensionNumbersResponse: extNum := r.GetAllExtensionNumbersResponse().ExtensionNumber sort.Sort(intArray(extNum)) if r.GetAllExtensionNumbersResponse().BaseTypeName != test.typeName || @@ -519,12 +536,12 @@ func testAllExtensionNumbersOfType(t *testing.T, stream v1alphagrpc.ServerReflec } } -func testAllExtensionNumbersOfTypeError(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient) { +func testAllExtensionNumbersOfTypeError(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient) { for _, test := range []string{ "grpc.testing.ToBeExtendedE", } { - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_AllExtensionNumbersOfType{ + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_AllExtensionNumbersOfType{ AllExtensionNumbersOfType: test, }, }); err != nil { @@ -537,16 +554,16 @@ func testAllExtensionNumbersOfTypeError(t *testing.T, stream v1alphagrpc.ServerR } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_ErrorResponse: + case *v1pb.ServerReflectionResponse_ErrorResponse: default: t.Errorf("AllExtensionNumbersOfType(%v) = %v, want type ", test, r.MessageResponse) } } } -func testListServices(t *testing.T, stream v1alphagrpc.ServerReflection_ServerReflectionInfoClient) { - if err := stream.Send(&v1alphapb.ServerReflectionRequest{ - MessageRequest: &v1alphapb.ServerReflectionRequest_ListServices{}, +func testListServices(t *testing.T, stream v1grpc.ServerReflection_ServerReflectionInfoClient) { + if err := stream.Send(&v1pb.ServerReflectionRequest{ + MessageRequest: &v1pb.ServerReflectionRequest_ListServices{}, }); err != nil { t.Fatalf("failed to send request: %v", err) } @@ -557,11 +574,12 @@ func testListServices(t *testing.T, stream v1alphagrpc.ServerReflection_ServerRe } switch r.MessageResponse.(type) { - case *v1alphapb.ServerReflectionResponse_ListServicesResponse: + case *v1pb.ServerReflectionResponse_ListServicesResponse: services := r.GetListServicesResponse().Service want := []string{ "grpc.testingv3.SearchServiceV3", "grpc.testing.SearchService", + "grpc.reflection.v1.ServerReflection", "grpc.reflection.v1alpha.ServerReflection", "grpc.testing.DynamicService", } @@ -607,3 +625,84 @@ func registerDynamicProto(srv *grpc.Server, fdp *descriptorpb.FileDescriptorProt srv.RegisterService(sd, struct{}{}) } } + +type v1AlphaClientAdapter struct { + stub v1alphagrpc.ServerReflectionClient +} + +func (v v1AlphaClientAdapter) ServerReflectionInfo(ctx context.Context, opts ...grpc.CallOption) (v1grpc.ServerReflection_ServerReflectionInfoClient, error) { + stream, err := v.stub.ServerReflectionInfo(ctx, opts...) + if err != nil { + return nil, err + } + return v1AlphaClientStreamAdapter{stream}, nil +} + +type v1AlphaClientStreamAdapter struct { + v1alphagrpc.ServerReflection_ServerReflectionInfoClient +} + +func (s v1AlphaClientStreamAdapter) Send(request *v1pb.ServerReflectionRequest) error { + return s.ServerReflection_ServerReflectionInfoClient.Send(v1ToV1AlphaRequest(request)) +} + +func (s v1AlphaClientStreamAdapter) Recv() (*v1pb.ServerReflectionResponse, error) { + resp, err := s.ServerReflection_ServerReflectionInfoClient.Recv() + if err != nil { + return nil, err + } + return v1AlphaToV1Response(resp), nil +} + +func v1AlphaToV1Response(v1alpha *v1alphapb.ServerReflectionResponse) *v1pb.ServerReflectionResponse { + var v1 v1pb.ServerReflectionResponse + v1.ValidHost = v1alpha.ValidHost + if v1alpha.OriginalRequest != nil { + v1.OriginalRequest = v1AlphaToV1Request(v1alpha.OriginalRequest) + } + switch mr := v1alpha.MessageResponse.(type) { + case *v1alphapb.ServerReflectionResponse_FileDescriptorResponse: + if mr != nil { + v1.MessageResponse = &v1pb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &v1pb.FileDescriptorResponse{ + FileDescriptorProto: mr.FileDescriptorResponse.GetFileDescriptorProto(), + }, + } + } + case *v1alphapb.ServerReflectionResponse_AllExtensionNumbersResponse: + if mr != nil { + v1.MessageResponse = &v1pb.ServerReflectionResponse_AllExtensionNumbersResponse{ + AllExtensionNumbersResponse: &v1pb.ExtensionNumberResponse{ + BaseTypeName: mr.AllExtensionNumbersResponse.GetBaseTypeName(), + ExtensionNumber: mr.AllExtensionNumbersResponse.GetExtensionNumber(), + }, + } + } + case *v1alphapb.ServerReflectionResponse_ListServicesResponse: + if mr != nil { + svcs := make([]*v1pb.ServiceResponse, len(mr.ListServicesResponse.GetService())) + for i, svc := range mr.ListServicesResponse.GetService() { + svcs[i] = &v1pb.ServiceResponse{ + Name: svc.GetName(), + } + } + v1.MessageResponse = &v1pb.ServerReflectionResponse_ListServicesResponse{ + ListServicesResponse: &v1pb.ListServiceResponse{ + Service: svcs, + }, + } + } + case *v1alphapb.ServerReflectionResponse_ErrorResponse: + if mr != nil { + v1.MessageResponse = &v1pb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1pb.ErrorResponse{ + ErrorCode: mr.ErrorResponse.GetErrorCode(), + ErrorMessage: mr.ErrorResponse.GetErrorMessage(), + }, + } + } + default: + // no value set + } + return &v1 +}