Sanath Manavarte
Sanath Manavarte

Reputation: 104

Testing gRPC server with golang and mockery fails with a timeout when mock fails

I am trying to test a gRPC service locally.

Here is the sample code

type TestGrpcServer struct {
    t      *testing.T
    Server *grpc.Server
    Lis    *bufconn.Listener
    Conn   *grpc.ClientConn
}

func (s *TestGrpcServer) Serve() {
    go func() {
        if err := s.Server.Serve(s.Lis); err != nil {
            s.t.Fail()
        }
    }()

    var err error
    s.Conn, err = grpc.DialContext(
        context.Background(),
        "",
        grpc.WithContextDialer(
            func(ctx context.Context, str string) (net.Conn, error) {
                return s.Lis.Dial()
            },
        ), grpc.WithTransportCredentials(insecure.NewCredentials()),
    )
    require.NoError(s.t, err)
}

func (s *TestGrpcServer) Stop() {
    s.Conn.Close()
    s.Server.Stop()
}

func NewTestGrpcServer(t *testing.T) *TestGrpcServer {
    buffer := 101024 * 1024
    lis := bufconn.Listen(buffer)
    s := grpc.NewServer()

    return &TestGrpcServer{
        t:      t,
        Server: s,
        Lis:    lis,
        Conn:   nil,
    }
}

func TestRPC(t *testing.T) {
    s := NewTestGrpcServer(t)
        
    // I used mockery to generate this mock
    // Let's say this has a function - Create
    mockInterface := NewMockInterface(t)  

    service := NewGrpcService(mockInterface)  // This is an implementation of a GRPC service
    pb.RegisterGrpcService(s.Server, service)  // pb is my proto generated package

    s.Serve()
    defer s.Stop()
        
    // I am going to intentionally pass a value which will not pass this mock.
    mockInterface.On("Create", 13, mock.Anything).Return(modelComputeNode, nil)
    client := pb.NewGrpcServiceClient(s.Conn)
        
    ctx := context.Background()
    val, err := client.Create(ctx, &CreateMessage{12, "foobar"})

    // Deep inside mock, the mock fails with t.FailNow(). 
    // But, the test does not fail immediately. It times out after the configured time instead.
}

I think this is because the server is still "serving", and the defer method on the stop has not yet been called. I expected the defer to be executed after failNow though, but didn't happen (added a debug breakpoint inside the Stop function to verify.

Am I missing something?

Upvotes: 2

Views: 547

Answers (0)

Related Questions