test(server): notes service
parent
ad530b28da
commit
0f1ad91770
|
@ -7,6 +7,7 @@
|
|||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
bin/*
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
|
7
main.go
7
main.go
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"errors"
|
||||
"github.com/sundowndev/grpc-api-example/server"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"io"
|
||||
"net"
|
||||
|
@ -16,8 +17,8 @@ func main() {
|
|||
log := grpclog.NewLoggerV2(os.Stdout, io.Discard, io.Discard)
|
||||
grpclog.SetLoggerV2(log)
|
||||
|
||||
addr := "0.0.0.0:10000"
|
||||
srv := server.NewServer()
|
||||
addr := "0.0.0.0:10000" // TODO: handle this with CLI flags
|
||||
srv := server.NewServer(insecure.NewCredentials()) // TODO: Replace with your own certificate!
|
||||
|
||||
// Serve gRPC Server
|
||||
log.Info("Serving gRPC on https://", addr)
|
||||
|
@ -39,4 +40,6 @@ func main() {
|
|||
if err := srv.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Info("graceful shut down succeeded")
|
||||
}
|
||||
|
|
|
@ -14,7 +14,10 @@ type NotesService struct {
|
|||
}
|
||||
|
||||
func NewNotesService() *NotesService {
|
||||
return &NotesService{}
|
||||
return &NotesService{
|
||||
mu: &sync.RWMutex{},
|
||||
notes: make([]*notesv1.Note, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NotesService) ListNotes(_ *notesv1.ListNotesRequest, srv notesv1.NotesService_ListNotesServer) error {
|
||||
|
@ -32,15 +35,15 @@ func (s *NotesService) ListNotes(_ *notesv1.ListNotesRequest, srv notesv1.NotesS
|
|||
}
|
||||
|
||||
func (s *NotesService) AddNote(_ context.Context, req *notesv1.AddNoteRequest) (*notesv1.AddNoteResponse, error) {
|
||||
n := ¬esv1.Note{
|
||||
note := ¬esv1.Note{
|
||||
Id: uuid.Must(uuid.NewV4()).String(),
|
||||
Title: req.Title,
|
||||
Archived: false,
|
||||
}
|
||||
|
||||
s.notes = append(s.notes, n)
|
||||
s.notes = append(s.notes, note)
|
||||
|
||||
return ¬esv1.AddNoteResponse{
|
||||
Note: n,
|
||||
Note: note,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -2,56 +2,112 @@ package server
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
notesv1 "github.com/sundowndev/grpc-api-example/proto/notes/v1"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
"io"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func newTestServer() (*Server, *grpc.ClientConn, error) {
|
||||
srv := NewServer(insecure.NewCredentials())
|
||||
buffer := 101024 * 1024
|
||||
lis := bufconn.Listen(buffer)
|
||||
srv.listener = lis
|
||||
go srv.grpcSrv.Serve(lis)
|
||||
|
||||
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 {
|
||||
_ = srv.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return srv, conn, nil
|
||||
}
|
||||
|
||||
func TestNotesService_ListNotes(t *testing.T) {
|
||||
addr := "0.0.0.0:10000"
|
||||
srv := NewServer()
|
||||
go srv.Listen(addr)
|
||||
defer srv.Close()
|
||||
|
||||
conn, err := grpc.DialContext(context.Background(), addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := notesv1.NewNotesServiceClient(conn)
|
||||
res, err := client.ListNotes(context.TODO(), ¬esv1.ListNotesRequest{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
testcases := []struct {
|
||||
name string
|
||||
notes []*notesv1.Note
|
||||
}{
|
||||
{
|
||||
name: "test with no notes",
|
||||
notes: []*notesv1.Note{},
|
||||
},
|
||||
{
|
||||
name: "test with few notes",
|
||||
notes: []*notesv1.Note{
|
||||
{Title: "test note 1", Archived: false},
|
||||
{Title: "note 2", Archived: true},
|
||||
{Title: "note 3", Archived: false},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.NotNil(t, res)
|
||||
for _, tt := range testcases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
srv, conn, err := newTestServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
client := notesv1.NewNotesServiceClient(conn)
|
||||
defer srv.Close()
|
||||
defer conn.Close()
|
||||
|
||||
//err = res.RecvMsg()
|
||||
//if err != nil && !errors.Is(err, io.EOF) {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
for _, note := range tt.notes {
|
||||
_, err := client.AddNote(context.Background(), ¬esv1.AddNoteRequest{Title: note.Title})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
res, err := client.ListNotes(context.Background(), ¬esv1.ListNotesRequest{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
notes := make([]*notesv1.Note, 0)
|
||||
|
||||
for {
|
||||
recv, err := res.Recv()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
notes = append(notes, recv.Note)
|
||||
}
|
||||
|
||||
assert.Len(t, notes, len(tt.notes))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotesService_AddNote(t *testing.T) {
|
||||
addr := "0.0.0.0:10000"
|
||||
srv := NewServer()
|
||||
go srv.Listen(addr)
|
||||
defer srv.Close()
|
||||
|
||||
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
srv, conn, err := newTestServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
client := notesv1.NewNotesServiceClient(conn)
|
||||
defer srv.Close()
|
||||
defer conn.Close()
|
||||
|
||||
client := notesv1.NewNotesServiceClient(conn)
|
||||
res, err := client.AddNote(context.TODO(), ¬esv1.AddNoteRequest{Title: "test note"})
|
||||
res, err := client.AddNote(context.Background(), ¬esv1.AddNoteRequest{Title: "test note"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.NotNil(t, res)
|
||||
assert.Equal(t, "test note", res.Note.Title)
|
||||
assert.Equal(t, false, res.Note.Archived)
|
||||
}
|
||||
|
|
|
@ -5,25 +5,23 @@ import (
|
|||
"fmt"
|
||||
notesv1 "github.com/sundowndev/grpc-api-example/proto/notes/v1"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
listener net.Listener
|
||||
srv *grpc.Server
|
||||
grpcSrv *grpc.Server
|
||||
}
|
||||
|
||||
func NewServer() *Server {
|
||||
func NewServer(c credentials.TransportCredentials) *Server {
|
||||
s := grpc.NewServer(
|
||||
// TODO: Replace with your own certificate!
|
||||
grpc.Creds(insecure.NewCredentials()),
|
||||
grpc.Creds(c),
|
||||
)
|
||||
notesv1.RegisterNotesServiceServer(s, NewNotesService())
|
||||
|
||||
srv := &Server{
|
||||
srv: s,
|
||||
grpcSrv: s,
|
||||
}
|
||||
srv.registerServices()
|
||||
|
||||
return srv
|
||||
}
|
||||
|
@ -31,16 +29,20 @@ func NewServer() *Server {
|
|||
func (s *Server) Listen(addr string) error {
|
||||
lis, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to listen: %e", err)
|
||||
return fmt.Errorf("failed to listen: %v", err)
|
||||
}
|
||||
s.listener = lis
|
||||
return s.srv.Serve(s.listener)
|
||||
return s.grpcSrv.Serve(s.listener)
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
s.srv.GracefulStop()
|
||||
s.grpcSrv.GracefulStop()
|
||||
if err := s.listener.Close(); !errors.Is(err, net.ErrClosed) {
|
||||
return err
|
||||
return fmt.Errorf("error closing server: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) registerServices() {
|
||||
notesv1.RegisterNotesServiceServer(s.grpcSrv, NewNotesService())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue