Skip to content

Commit

Permalink
Start new server automatically (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
nhatthm authored Dec 10, 2021
1 parent dbacb4e commit ad1903b
Show file tree
Hide file tree
Showing 12 changed files with 406 additions and 261 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ go get github.com/nhatthm/grpcmock

### Mock a gRPC server

Read more about [mocking a gRPC server](SERVER.md)
Read more about [mocking a gRPC server](resources/docs/SERVER.md)

[<sub><sup>[table of contents]</sup></sub>](#table-of-contents)

#### Unary Method

Read more about [mocking a Unary Method](SERVER.md#mock-a-unary-method)
Read more about [mocking a Unary Method](resources/docs/SERVER.md#mock-a-unary-method)

```go
package main
Expand All @@ -69,7 +69,7 @@ func TestGetItems(t *testing.T) {

expected := &Item{Id: 42, Name: "Item 42"}

_, d := grpcmock.MockAndStartServer(
_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterService(RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectUnary("myservice/GetItem").
Expand Down Expand Up @@ -101,7 +101,7 @@ func TestGetItems(t *testing.T) {

#### Client-Stream Method

Read more about [mocking a Client-Stream Method](SERVER.md#mock-a-client-stream-method)
Read more about [mocking a Client-Stream Method](resources/docs/SERVER.md#mock-a-client-stream-method)

```go
package main
Expand All @@ -121,7 +121,7 @@ func TestCreateItems(t *testing.T) {

expected := &CreateItemsResponse{NumItems: 1}

_, d := grpcmock.MockAndStartServer(
_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterService(RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectClientStream("myservice/CreateItems").
Expand Down Expand Up @@ -149,7 +149,7 @@ func TestCreateItems(t *testing.T) {

#### Server-Stream Method

Read more about [mocking a Server-Stream Method](SERVER.md#mock-a-server-stream-method)
Read more about [mocking a Server-Stream Method](resources/docs/SERVER.md#mock-a-server-stream-method)

```go
package main
Expand All @@ -172,7 +172,7 @@ func TestListItems(t *testing.T) {
{Id: 42, Name: "Item 42"},
}

_, d := grpcmock.MockAndStartServer(
_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterService(RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectServerStream("myservice/ListItems").
Expand Down Expand Up @@ -207,7 +207,7 @@ func TestListItems(t *testing.T) {

#### Bidirectional-Stream Method

Read more about [mocking a Bidirectional-Stream Method](SERVER.md#mock-a-bidirectional-stream-method)
Read more about [mocking a Bidirectional-Stream Method](resources/docs/SERVER.md#mock-a-bidirectional-stream-method)

```go
package main
Expand All @@ -234,7 +234,7 @@ func TestTransformItems(t *testing.T) {
{Id: 42, Name: "Item 42"},
}

_, d := grpcmock.MockAndStartServer(
_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterService(RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectBidirectionalStream("myservice/TransformItems").
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ require (
github.com/stretchr/objx v0.3.0 // indirect
github.com/yudai/gojsondiff v1.0.0 // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
golang.org/x/net v0.0.0-20211203184738-4852103109b8 // indirect
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211203184738-4852103109b8 h1:PFkPt/jI9Del3hmFplBtRp8tDhSRpFu7CyRs7VmEC0M=
golang.org/x/net v0.0.0-20211203184738-4852103109b8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -191,8 +191,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
Expand Down Expand Up @@ -221,8 +221,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9 h1:fU3FNfL/oBU2D5DvGqiuyVqqn40DdxvaTFHq7aivA3k=
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
Expand Down
4 changes: 4 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ func serviceSorter(services []*grpc.ServiceDesc) ([]*grpc.ServiceDesc, func(i, j
return services[i].ServiceName < services[j].ServiceName
}
}

func closeNothing() error {
return nil
}
6 changes: 6 additions & 0 deletions helper_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,9 @@ func TestServiceSorter(t *testing.T) {

assert.Equal(t, expected, actual)
}

func TestCloseNothing(t *testing.T) {
t.Parallel()

assert.NoError(t, closeNothing())
}
44 changes: 20 additions & 24 deletions mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package grpcmock
import (
"context"
"net"
"time"

"github.com/stretchr/testify/assert"
"google.golang.org/grpc/test/bufconn"
Expand All @@ -15,44 +14,41 @@ type ServerMocker func(t T) *Server
// ServerMockerWithContextDialer starts a new mocked server with a bufconn and returns it as a context dialer for the grpc.DialOption.
type ServerMockerWithContextDialer func(t T) (*Server, ContextDialer)

// MockServer mocks the server and ensures all the expectations were met at the end of the test.
func MockServer(opts ...ServerOption) ServerMocker {
// MockUnstartedServer mocks the server and ensures all the expectations were met at the end of the test.
func MockUnstartedServer(opts ...ServerOption) ServerMocker {
return func(t T) *Server {
s := NewServer(opts...).WithTest(t)
s := NewUnstartedServer(opts...).WithTest(t)

t.Cleanup(func() {
assert.NoError(t, s.ExpectationsWereMet())

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

_ = s.Close(ctx) // nolint: errcheck
})

return s
}
}

// MockAndStartServer starts a new mocked server with bufconn and ensures all the expectations were met at the end of the test.
func MockAndStartServer(opts ...ServerOption) ServerMockerWithContextDialer {
return func(t T) (*Server, ContextDialer) {
buf := bufconn.Listen(1024 * 1024)
s := MockServer(opts...)(t)

go func() {
defer buf.Close() // nolint: errcheck

_ = s.Serve(buf) // nolint: errcheck
}()
// MockServer starts a new mocked server and ensures all the expectations were met at the end of the test.
func MockServer(opts ...ServerOption) ServerMocker {
return func(t T) *Server {
s := NewServer(opts...)

t.Cleanup(func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
assert.NoError(t, s.ExpectationsWereMet())

_ = s.Close(ctx) // nolint: errcheck
_ = s.Close() // nolint: errcheck
})

return s, func(ctx context.Context, s string) (net.Conn, error) {
return s
}
}

// MockServerWithBufConn starts a new mocked server with bufconn and ensures all the expectations were met at the end of the test.
func MockServerWithBufConn(opts ...ServerOption) ServerMockerWithContextDialer {
return func(t T) (*Server, ContextDialer) {
buf := bufconn.Listen(1024 * 1024)
opts = append(opts, WithListener(buf))

return MockServer(opts...)(t), func(ctx context.Context, s string) (net.Conn, error) {
return buf.Dial()
}
}
Expand Down
68 changes: 63 additions & 5 deletions mock_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,76 @@ import (
"github.com/nhatthm/grpcmock/internal/grpctest"
)

func ExampleMockAndStartServer() {
func ExampleMockServer() {
// Simulate a test function.
//
// In reality, it's just straightforward:
// func TestMockAndStartServer(t *testing.T) {
// t.Parallel()
//
// s, d := grpcmock.MockAndStartServer()
// s, d := grpcmock.MockServer()
// // Client call and assertions.
// }
TestMockAndStartServer := func(t grpcmock.T) {
_, d := grpcmock.MockAndStartServer(
TestMockServer := func(t grpcmock.T) {
srv := grpcmock.MockServer(
grpcmock.RegisterService(grpctest.RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectUnary("grpctest.ItemService/GetItem").
WithPayload(&grpctest.GetItemRequest{Id: 41}).
Return(&grpctest.Item{
Id: 41,
Locale: "en-US",
Name: "Item #41",
})
},
)(t)

// Call the service.
out := &grpctest.Item{}
method := fmt.Sprintf("%s/grpctest.ItemService/GetItem", srv.Address())
err := grpcmock.InvokeUnary(context.Background(),
method, &grpctest.GetItemRequest{Id: 41}, out,
grpcmock.WithInsecure(),
)

expected := &grpctest.Item{
Id: 41,
Locale: "en-US",
Name: "Item #41",
}

require.NoError(t, err)
grpcAssert.EqualMessage(t, expected, out)

output, err := json.MarshalIndent(out, "", " ")
require.NoError(t, err)

// Output for the example.
fmt.Println(string(output))
}

TestMockServer(grpcmock.NoOpT())

// Output:
// {
// "id": 41,
// "locale": "en-US",
// "name": "Item #41"
// }
}

func ExampleMockServerWithBufConn() {
// Simulate a test function.
//
// In reality, it's just straightforward:
// func TestMockAndStartServer(t *testing.T) {
// t.Parallel()
//
// s, d := grpcmock.MockServerWithBufConn()
// // Client call and assertions.
// }
TestMockServerWithBufConn := func(t grpcmock.T) {
_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterService(grpctest.RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectUnary("grpctest.ItemService/GetItem").
Expand Down Expand Up @@ -60,7 +118,7 @@ func ExampleMockAndStartServer() {
fmt.Println(string(output))
}

TestMockAndStartServer(grpcmock.NoOpT())
TestMockServerWithBufConn(grpcmock.NoOpT())

// Output:
// {
Expand Down
Loading

0 comments on commit ad1903b

Please sign in to comment.