diff --git a/pkg/grpc/mock.go b/pkg/grpc/mock.go new file mode 100644 index 0000000..c57c8f2 --- /dev/null +++ b/pkg/grpc/mock.go @@ -0,0 +1,50 @@ +package grpc + +import ( + "context" + "net" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "go.uber.org/fx" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/test/bufconn" +) + +func StartTestGrpcService(lc fx.Lifecycle, server GrpcServer, logger *zerolog.Logger) *grpc.ClientConn { + buffer := 101024 * 1024 + lis := bufconn.Listen(buffer) + + baseServer := server.GetGrpcServer() + go func() { + if err := baseServer.Serve(lis); err != nil { + logger.Printf("error serving server: %v", err) + } + }() + + conn, err := grpc.DialContext(context.Background(), "", + grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { + return lis.Dial() + }), grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + logger.Printf("error connecting to server: %v", err) + } + + closer := func() { + err := lis.Close() + if err != nil { + log.Printf("error closing listener: %v", err) + } + baseServer.Stop() + } + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + closer() + return nil + }, + }) + + return conn +} diff --git a/pkg/grpc/module.go b/pkg/grpc/module.go new file mode 100644 index 0000000..ab13ec3 --- /dev/null +++ b/pkg/grpc/module.go @@ -0,0 +1,9 @@ +package grpc + +import "go.uber.org/fx" + +var Module = fx.Options( + fx.Provide( + NewServer, + ), +) diff --git a/pkg/grpc/server.go b/pkg/grpc/server.go new file mode 100644 index 0000000..7fec024 --- /dev/null +++ b/pkg/grpc/server.go @@ -0,0 +1,56 @@ +package grpc + +import ( + "context" + "fmt" + "net" + + "github.com/rs/zerolog" + "google.golang.org/grpc" +) + +type BareServer struct { + Server *grpc.Server +} + +func NewServer(logger *zerolog.Logger) *BareServer { + grpcServer := &BareServer{} + + sv := grpc.NewServer( + grpc.UnaryInterceptor( + grpcLoggerInterceptor(logger), + ), + ) + grpcServer.Server = sv + + return grpcServer +} + +func (s *BareServer) GetListener() (net.Listener, error) { + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 50051)) + if err != nil { + return nil, err + } + + return lis, nil +} + +func (s *BareServer) GetGrpcServer() *grpc.Server { + return s.Server +} + +func grpcLoggerInterceptor(logger *zerolog.Logger) func(context.Context, interface{}, *grpc.UnaryServerInfo, grpc.UnaryHandler) (interface{}, error) { + return func(ctx context.Context, + req interface{}, + _ *grpc.UnaryServerInfo, + handler grpc.UnaryHandler, + ) (interface{}, error) { + // Add logger to context + lctx := logger.WithContext(ctx) + + // Calls the handler + h, err := handler(lctx, req) + + return h, err + } +} diff --git a/pkg/grpc/snapshot.go b/pkg/grpc/snapshot.go new file mode 100644 index 0000000..90faebe --- /dev/null +++ b/pkg/grpc/snapshot.go @@ -0,0 +1,16 @@ +package grpc + +import "strings" + +type ProtoMessage interface { + String() string +} + +// StringifySnapshot converts a protobuf response to a string and removes all double spaces. +// This is needed because of a pseudo-random effect https://github.com/golang/protobuf/issues/1121 +func StringifySnapshot(resp ProtoMessage) string { + respStr := resp.String() + respStr = strings.ReplaceAll(respStr, " ", " ") + + return respStr +}