add tests

This commit is contained in:
Dawid Wysokiński 2023-05-07 07:01:56 +02:00
parent 9d402178c2
commit c2769a233e
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892
5 changed files with 247 additions and 96 deletions

View File

@ -6,7 +6,6 @@ import (
"crypto/x509"
"errors"
"fmt"
"io"
"log"
"net"
"os"
@ -14,17 +13,16 @@ import (
"syscall"
"gitea.dwysokinski.me/Kichiyaki/grpc-g2a/cmd/internal"
"gitea.dwysokinski.me/Kichiyaki/grpc-g2a/internal/greeter"
"gitea.dwysokinski.me/Kichiyaki/grpc-g2a/proto"
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
"go.uber.org/zap"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
_ "google.golang.org/grpc/encoding/gzip"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
@ -101,9 +99,7 @@ func newServer(address string, logger *zap.Logger) (*server, error) {
),
)
proto.RegisterGreeterServer(srv, &greeterServer{
logger: logger,
})
proto.RegisterGreeterServer(srv, greeter.NewServer(logger))
return &server{
lis: lis,
@ -150,91 +146,3 @@ func createPanicHandler(logger *zap.Logger) grpc_recovery.RecoveryHandlerFunc {
return status.Errorf(codes.Internal, "internal server error")
}
}
type greeterServer struct {
proto.UnimplementedGreeterServer
logger *zap.Logger
}
func (g *greeterServer) SayHello(ctx context.Context, r *proto.HelloRequest) (*proto.HelloReply, error) {
md, ok := metadata.FromIncomingContext(ctx)
if ok {
g.logger.Debug("received metadata", zap.Any("metadata", md))
}
return &proto.HelloReply{
Message: buildHelloMsg(r.GetName()),
}, nil
}
func (g *greeterServer) SayHelloToJames(_ context.Context, r *proto.HelloRequest) (*proto.HelloReply, error) {
name := r.GetName()
if name != "James" {
st, err := status.
New(codes.InvalidArgument, "invalid name").
WithDetails(&errdetails.BadRequest{
FieldViolations: []*errdetails.BadRequest_FieldViolation{
{
Field: "name",
Description: "must be James",
},
},
})
if err != nil {
return nil, status.New(codes.Internal, "internal server error").Err()
}
return nil, st.Err()
}
return &proto.HelloReply{
Message: buildHelloMsg(name),
}, nil
}
func (g *greeterServer) SayHelloServerStream(r *proto.MultiHelloRequest, stream proto.Greeter_SayHelloServerStreamServer) error {
for _, n := range r.GetNames() {
if err := stream.Send(&proto.HelloReply{
Message: buildHelloMsg(n),
}); err != nil {
return err
}
}
return nil
}
func (g *greeterServer) SayHelloClientStream(stream proto.Greeter_SayHelloClientStreamServer) error {
var messages []string
for {
r, err := stream.Recv()
if errors.Is(err, io.EOF) {
return stream.SendAndClose(&proto.MultiHelloReply{
Messages: messages,
})
}
if err != nil {
return fmt.Errorf("stream returned error: %w", err)
}
messages = append(messages, buildHelloMsg(r.GetName()))
}
}
func (g *greeterServer) SayHelloBidirectionalStream(stream proto.Greeter_SayHelloBidirectionalStreamServer) error {
for {
r, err := stream.Recv()
if errors.Is(err, io.EOF) {
return nil
}
if err != nil {
return fmt.Errorf("stream returned error: %w", err)
}
if err = stream.Send(&proto.HelloReply{Message: buildHelloMsg(r.GetName())}); err != nil {
return fmt.Errorf("couldn't send reply: %w", err)
}
}
}
func buildHelloMsg(name string) string {
return "Hello " + name + "!"
}

6
go.mod
View File

@ -5,17 +5,21 @@ go 1.20
require (
github.com/google/uuid v1.3.0
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/stretchr/testify v1.8.2
go.uber.org/zap v1.24.0
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f
google.golang.org/grpc v1.54.0
google.golang.org/protobuf v1.30.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

11
go.sum
View File

@ -35,8 +35,10 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vb
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
@ -47,11 +49,16 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
@ -133,11 +140,13 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

107
internal/greeter/server.go Normal file
View File

@ -0,0 +1,107 @@
package greeter
import (
"context"
"errors"
"fmt"
"io"
"gitea.dwysokinski.me/Kichiyaki/grpc-g2a/proto"
"go.uber.org/zap"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
type Server struct {
proto.UnimplementedGreeterServer
logger *zap.Logger
}
func NewServer(logger *zap.Logger) *Server {
return &Server{logger: logger}
}
func (s *Server) SayHello(ctx context.Context, r *proto.HelloRequest) (*proto.HelloReply, error) {
md, ok := metadata.FromIncomingContext(ctx)
if ok {
s.logger.Debug("received metadata", zap.Any("metadata", md))
}
return &proto.HelloReply{
Message: buildHelloMsg(r.GetName()),
}, nil
}
func (s *Server) SayHelloToJames(_ context.Context, r *proto.HelloRequest) (*proto.HelloReply, error) {
name := r.GetName()
if name != "James" {
st, err := status.
New(codes.InvalidArgument, "invalid name").
WithDetails(&errdetails.BadRequest{
FieldViolations: []*errdetails.BadRequest_FieldViolation{
{
Field: "name",
Description: "must be James",
},
},
})
if err != nil {
return nil, status.New(codes.Internal, "internal server error").Err()
}
return nil, st.Err()
}
return &proto.HelloReply{
Message: buildHelloMsg(name),
}, nil
}
func (s *Server) SayHelloServerStream(r *proto.MultiHelloRequest, stream proto.Greeter_SayHelloServerStreamServer) error {
for _, n := range r.GetNames() {
if err := stream.Send(&proto.HelloReply{
Message: buildHelloMsg(n),
}); err != nil {
return err
}
}
return nil
}
func (s *Server) SayHelloClientStream(stream proto.Greeter_SayHelloClientStreamServer) error {
var messages []string
for {
r, err := stream.Recv()
if errors.Is(err, io.EOF) {
return stream.SendAndClose(&proto.MultiHelloReply{
Messages: messages,
})
}
if err != nil {
return fmt.Errorf("stream returned error: %w", err)
}
messages = append(messages, buildHelloMsg(r.GetName()))
}
}
func (s *Server) SayHelloBidirectionalStream(stream proto.Greeter_SayHelloBidirectionalStreamServer) error {
for {
r, err := stream.Recv()
if errors.Is(err, io.EOF) {
return nil
}
if err != nil {
return fmt.Errorf("stream returned error: %w", err)
}
if err = stream.Send(&proto.HelloReply{Message: buildHelloMsg(r.GetName())}); err != nil {
return fmt.Errorf("couldn't send reply: %w", err)
}
}
}
func buildHelloMsg(name string) string {
return "Hello " + name + "!"
}

View File

@ -0,0 +1,123 @@
package greeter_test
import (
"context"
"errors"
"io"
"net"
"testing"
"gitea.dwysokinski.me/Kichiyaki/grpc-g2a/internal/greeter"
"gitea.dwysokinski.me/Kichiyaki/grpc-g2a/proto"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/test/bufconn"
)
func TestServer_SayHello(t *testing.T) {
t.Parallel()
tests := []struct {
name string
expected string
}{
{
name: "James",
expected: "Hello James!",
},
{
name: "Robert",
expected: "Hello Robert!",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
conn := newServer(t)
reply, err := conn.SayHello(context.Background(), &proto.HelloRequest{Name: tt.name})
require.NoError(t, err)
assert.Equal(t, tt.expected, reply.GetMessage())
})
}
}
func TestServer_SayHelloBidirectionalStream(t *testing.T) {
t.Parallel()
names := make([]string, 20)
for i := range names {
names[i] = uuid.NewString()
}
client := newServer(t)
streamClient, err := client.SayHelloBidirectionalStream(context.Background())
require.NoError(t, err)
for _, n := range names {
err = streamClient.Send(&proto.HelloRequest{
Name: n,
})
assert.NoError(t, err)
}
assert.NoError(t, streamClient.CloseSend())
replies := make([]*proto.HelloReply, 0, len(names))
for {
reply, err := streamClient.Recv()
if errors.Is(err, io.EOF) {
break
}
assert.NoError(t, err)
replies = append(replies, reply)
}
require.Len(t, replies, len(names))
for _, n := range names {
found := false
for _, r := range replies {
if r.GetMessage() == "Hello "+n+"!" {
found = true
break
}
}
assert.True(t, found, "name="+n)
}
}
func newServer(t *testing.T) proto.GreeterClient {
buffer := 101024 * 1024
lis := bufconn.Listen(buffer)
server := grpc.NewServer()
proto.RegisterGreeterServer(server, greeter.NewServer(zap.NewNop()))
go func() {
require.NoError(t, server.Serve(lis))
}()
t.Cleanup(func() {
server.GracefulStop()
})
conn, err := grpc.Dial(
"",
grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, conn.Close())
})
return proto.NewGreeterClient(conn)
}