generated from broadinstitute/golang-project-template
-
Notifications
You must be signed in to change notification settings - Fork 1
/
common.go
83 lines (71 loc) · 2.47 KB
/
common.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package testing
import (
"context"
"google.golang.org/api/option"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/status"
"net"
"testing"
)
type grpcServer struct {
server *grpc.Server
clientOptions []option.ClientOption
}
// NotFoundError convenience constructor for returning a not found error in mocks
func NotFoundError() error {
return status.Error(codes.NotFound, "Not found")
}
// construct a new fake grpc server
// reference: https://github.com/googleapis/google-cloud-go/blob/main/testing.md#testing-grpc-services-using-fakes
func newFakeGRPCServer(t *testing.T, registerMockBackends func(server *grpc.Server)) grpcServer {
// Create a GRPC server
listener, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatal(err)
}
gsrv := grpc.NewServer(grpc.UnaryInterceptor(convertPanicIntoErrorInterceptor))
t.Cleanup(func() {
gsrv.Stop()
})
// register mock backends with the server
registerMockBackends(gsrv)
// start server in async goroutine
go func() {
if err := gsrv.Serve(listener); err != nil {
// we can't use t.Fatal err since we're in a separate goroutine
panic(err)
}
}()
// Create client that is configured to talk to the fake GRPC server
fakeServerAddr := listener.Addr().String()
return grpcServer{
server: gsrv,
clientOptions: []option.ClientOption{
option.WithEndpoint(fakeServerAddr),
option.WithoutAuthentication(),
option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
},
}
}
// convertPanicIntoErrorInterceptor detects when a handler panics and returns it as a GRPC error.
// This is useful because we are using mockery-generated Testify mocks as Google API GRPC backends.
// The mocks panic when an unexpected call is made. This interceptor will recover the panic,
// convert it into a GRPC error and return it to the client.
// This is desirable because it causes the individual test case to fail gracefully (a panic seems to kill the entire go
// test run).
func convertPanicIntoErrorInterceptor(ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler) (result interface{}, err error) {
// Set up a defer function to intercept a panic
defer func() {
if panicErr := recover(); panicErr != nil {
// convert panic into a GRPC error that will be returned to client
err = status.Errorf(codes.Internal, "%v", panicErr)
}
}()
result, err = handler(ctx, req)
return
}