gRPC Testing¶
While Mayhem does not currently support native testing of gRPC servers, it does support gRPC server testing through the use of a gRPC gateway. The gateway comes with a protoc plugin. It reads a gRPC service definition and generates a reverse-proxy server which translates a RESTful JSON API into gRPC.
This guide will walk you through the steps to test a gRPC server. While this method can be used with any language, the guide assumes you're using go. If you're not and are having trouble following the steps for another language, let us know, we'll be happy to help out.
Live Example¶
A live example that follows this process is available in GitHub:
https://github.com/ForAllSecure/mapi-grpc-example
Installing gRPC-Gateway¶
Follow the instructions in the README. You'll need to have go and protoc installed.
Generate Server Stub¶
The following command generates the proxy stubs from your .proto
file:
protoc -I . --grpc-gateway_out . \
--grpc-gateway_opt logtostderr=true \
--grpc-gateway_opt paths=source_relative \
--grpc-gateway_opt generate_unbound_methods=true \
your/service/v1/your_service.proto
The command above generates the gateway stub at
your/service/v1/your_service.pb.gw.go
. We will import the stubs to write the
proxy.
Write an entrypoint for the proxy¶
We will now write the proxy in rest-proxy.go
. The proxy will listen on port
8081 and forward requests to your gRPC server.
package main
import (
"context"
"flag"
"net/http"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
gw "github.com/your-org/your-project/your/service/v1"
)
var (
// command-line options:
// gRPC server endpoint
grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:10990", "gRPC server endpoint")
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// Register gRPC server endpoint
// Note: Make sure the gRPC server is running properly and accessible
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := gw.RegisterYourServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)
if err != nil {
return err
}
// Start HTTP server (and proxy calls to gRPC server endpoint)
return http.ListenAndServe(":8081", mux)
}
func main() {
flag.Parse()
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}
You will need to change three things:
- The import line
"github.com/your-org/your-project/your/service/v1"
to match your project and the path to the stub you generated in the previous step. - The url to your gRPC server. The code above assumes your gRPC server is
listening on
localhost:10990
. - The call to
gw.RegisterYourServiceHandlerFromEndpoint
to match your service name. The function should be present in the gateway stub you generated earlier if you're not sure what the name should be.
Generate the OpenAPI Specification¶
The following command generates the OpenAPI specification:
protoc -I . --openapiv2_out . \
--openapiv2_opt logtostderr=true \
--openapiv2_opt generate_unbound_methods=true \
your/service/v1/your_service.proto
Test¶
- Start your gRPC server
- Start the proxy with
go run rest-proxy.go
- Create a target:
mapi target create target-name http://localhost:8081
- Test:
mapi run target-name 120 your/service/v1/your_service.openapi.json