Skip to content

Commit

Permalink
js/grpc: Tests for multi services in the same proto file
Browse files Browse the repository at this point in the history
It's an extension of grafana/k6#2265
  • Loading branch information
codebien committed Jan 11, 2022
1 parent 0c9e76f commit 7a96e0a
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 3 deletions.
17 changes: 14 additions & 3 deletions js/modules/k6/grpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ type fileDescriptorLookupKey struct ***REMOVED***
***REMOVED***

func resolveServiceFileDescriptors(
mc reflectpb.ServerReflection_ServerReflectionInfoClient,
client sendReceiver,
res *reflectpb.ListServiceResponse,
) (*descriptorpb.FileDescriptorSet, error) ***REMOVED***
services := res.GetService()
Expand All @@ -357,7 +357,7 @@ func resolveServiceFileDescriptors(
FileContainingSymbol: service.GetName(),
***REMOVED***,
***REMOVED***
resp, err := sendReceive(mc, req)
resp, err := sendReceive(client, req)
if err != nil ***REMOVED***
return nil, fmt.Errorf("can't get method on service %q: %w", service, err)
***REMOVED***
Expand All @@ -384,10 +384,21 @@ func resolveServiceFileDescriptors(
return fdset, nil
***REMOVED***

// sendReceiver is a smaller interface for decoupling
// from `reflectpb.ServerReflection_ServerReflectionInfoClient`,
// that has the dependency from `grpc.ClientStream`,
// which is too much in the case the requirement is to just make a reflection's request.
// It makes the API more restricted and with a controlled surface,
// in this way the testing should be easier also.
type sendReceiver interface ***REMOVED***
Send(*reflectpb.ServerReflectionRequest) error
Recv() (*reflectpb.ServerReflectionResponse, error)
***REMOVED***

// sendReceive sends a request to a reflection client and,
// receives a response.
func sendReceive(
client reflectpb.ServerReflection_ServerReflectionInfoClient,
client sendReceiver,
req *reflectpb.ServerReflectionRequest,
) (*reflectpb.ServerReflectionResponse, error) ***REMOVED***
if err := client.Send(req); err != nil ***REMOVED***
Expand Down
105 changes: 105 additions & 0 deletions js/modules/k6/grpc/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ import (
"bytes"
"context"
"errors"
"fmt"
"net/url"
"os"
"runtime"
"strings"
"sync/atomic"
"testing"

"google.golang.org/grpc/reflection"
reflectpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/descriptorpb"

"github.com/dop251/goja"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -761,3 +766,103 @@ func TestDebugStat(t *testing.T) ***REMOVED***
***REMOVED***)
***REMOVED***
***REMOVED***

func TestResolveFileDescriptors(t *testing.T) ***REMOVED***
t.Parallel()

tests := []struct ***REMOVED***
name string
pkgs []string
services []string
expectedDescriptors int
***REMOVED******REMOVED***
***REMOVED***
name: "SuccessSamePackage",
pkgs: []string***REMOVED***"mypkg"***REMOVED***,
services: []string***REMOVED***"Service1", "Service2", "Service3"***REMOVED***,
expectedDescriptors: 3,
***REMOVED***,
***REMOVED***
name: "SuccessMultiPackages",
pkgs: []string***REMOVED***"mypkg1", "mypkg2", "mypkg3"***REMOVED***,
services: []string***REMOVED***"Service", "Service", "Service"***REMOVED***,
expectedDescriptors: 3,
***REMOVED***,
***REMOVED***
name: "DeduplicateServices",
pkgs: []string***REMOVED***"mypkg1"***REMOVED***,
services: []string***REMOVED***"Service1", "Service2", "Service1"***REMOVED***,
expectedDescriptors: 2,
***REMOVED***,
***REMOVED***
name: "NoServices",
services: []string***REMOVED******REMOVED***,
expectedDescriptors: 0,
***REMOVED***,
***REMOVED***

for _, tt := range tests ***REMOVED***
tt := tt
t.Run(tt.name, func(t *testing.T) ***REMOVED***
t.Parallel()
var (
lsr = &reflectpb.ListServiceResponse***REMOVED******REMOVED***
mock = &getServiceFileDescriptorMock***REMOVED******REMOVED***
)
for i, service := range tt.services ***REMOVED***
// if only one package is defined then
// the package is the same for every service
pkg := tt.pkgs[0]
if len(tt.pkgs) > 1 ***REMOVED***
pkg = tt.pkgs[i]
***REMOVED***

lsr.Service = append(lsr.Service, &reflectpb.ServiceResponse***REMOVED***
Name: fmt.Sprintf("%s.%s", pkg, service),
***REMOVED***)
mock.pkgs = append(mock.pkgs, pkg)
mock.names = append(mock.names, service)
***REMOVED***

fdset, err := resolveServiceFileDescriptors(mock, lsr)
require.NoError(t, err)
assert.Len(t, fdset.File, tt.expectedDescriptors)
***REMOVED***)
***REMOVED***
***REMOVED***

type getServiceFileDescriptorMock struct ***REMOVED***
nreqs int64
pkgs []string
names []string
***REMOVED***

func (m *getServiceFileDescriptorMock) Send(req *reflectpb.ServerReflectionRequest) error ***REMOVED***
// TODO: check that the sent message is expected,
// otherwise return an error
return nil
***REMOVED***

func (m *getServiceFileDescriptorMock) Recv() (*reflectpb.ServerReflectionResponse, error) ***REMOVED***
n := atomic.AddInt64(&m.nreqs, 1)
ptr := func(s string) (sptr *string) ***REMOVED***
return &s
***REMOVED***
index := n - 1
fdp := &descriptorpb.FileDescriptorProto***REMOVED***
Package: ptr(m.pkgs[index]),
Name: ptr(m.names[index]),
***REMOVED***
b, err := proto.Marshal(fdp)
if err != nil ***REMOVED***
return nil, err
***REMOVED***
srr := &reflectpb.ServerReflectionResponse***REMOVED***
MessageResponse: &reflectpb.ServerReflectionResponse_FileDescriptorResponse***REMOVED***
FileDescriptorResponse: &reflectpb.FileDescriptorResponse***REMOVED***
FileDescriptorProto: [][]byte***REMOVED***b***REMOVED***,
***REMOVED***,
***REMOVED***,
***REMOVED***
return srr, nil
***REMOVED***

0 comments on commit 7a96e0a

Please sign in to comment.