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