测试使用TWIRP开发的RPC服务
Test RPC service developed in using TWIRP
我想测试一个示例 Twirp RPC 服务。示例服务来自 Twirp official website.
Protobuf定义如下:
syntax = "proto3";
package helloservice;
option go_package = "helloservice";
service HelloWorld {
rpc Hello(HelloReq) returns (HelloResp);
}
message HelloReq {
string subject = 1;
}
message HelloResp {
string text = 1;
}
服务器实现:
type HelloWorldServer struct{}
func (s *HelloWorldServer) Hello(ctx context.Context, req *pb.HelloReq) (*pb.HelloResp, error) {
return &pb.HelloResp{Text: "Hello " + req.Subject}, nil
}
我尝试了 ,但 ClientConn 与 HTTPClient 之间存在一些混淆。到目前为止,我有这个
var Once sync.Once
const bufSize = 1024 * 1024
var listener *bufconn.Listener
func InitTestServer(t *testing.T) *gomock.Controller {
Once.Do(func(){
listener = bufconn.Listen(bufSize)
server := &server.HelloWorldServer{}
twirpHandler := pb.NewHelloWorldServer(server, nil)
mux := http.NewServeMux()
mux.Handle(twirpHandler.PathPrefix(), twirpHandler)
httpServer := http.Server{
Handler: mux,
}
go func() {
if err := httpServer.Serve(listener); err != nil {
if err != http.ErrServerClosed {
log.Fatalln("Failed to start http listener", "error", err)
}
}
}()
})
ctrl := gomock.NewController(t)
return ctrl
}
func bufDialer(context.Context, string) (net.Conn, error) {
return listener.Dial()
}
func TestCreate(t *testing.T) {
//ctrl := InitTestServer(t)
InitTestServer(t)
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithInsecure(), grpc.WithContextDialer(bufDialer))
// conn is of type *ClientConn
if err != nil {
t.Fatalf("Failed to dial bufnet: %v", err)
}
defer conn.Close()
//NewHelloWorldJSONClient accepts only HTTPClient
client := pb.NewHelloWorldJSONClient(conn)
response, err := client.Hello(ctx, &pb.HelloReq{
Subject: "sample",
})
t.Log(response, err)
}
有什么方法可以将一种转换成另一种,或者有什么方法可以测试 Twirp RPC?
您可以使用 net/http/httptest
完成此类测试。
- 使用
pb.NewHelloWorldServer
创建处理程序并为其提供服务器实现结构。
- 使用处理程序创建
httptest.NewServer
。
- 在
pb.NewHelloWorldJSONClient
(或 protobuf,或两者)中使用 httptest 服务器的 .URL
。
举个简单的例子:
package main
import (
"context"
"net/http"
"net/http/httptest"
"testing"
pb "github.com/3ventic/twirphelloworld/rpc"
)
// InitTestServer initializes a test server for HelloWorld and returns its address
func InitTestServer() string {
handler := pb.NewHelloWorldServer(&HelloWorldServer{})
server := httptest.NewServer(handler)
return server.URL
}
func TestHello(t *testing.T) {
url := InitTestServer()
clients := map[string]pb.HelloWorld{
"json": pb.NewHelloWorldJSONClient(url, http.DefaultClient),
"pb": pb.NewHelloWorldProtobufClient(url, http.DefaultClient),
}
for typ, client := range clients {
t.Run(typ, func(t *testing.T) {
ctx := context.Background()
result, err := client.Hello(ctx, &pb.HelloReq{
Subject: "test",
})
if err != nil {
t.Error(err)
t.FailNow()
}
if result.Text != "Hello test" {
t.Errorf("result didn't match 'Hello test', was '%s'", result.Text)
}
})
}
}
我想测试一个示例 Twirp RPC 服务。示例服务来自 Twirp official website.
Protobuf定义如下:
syntax = "proto3";
package helloservice;
option go_package = "helloservice";
service HelloWorld {
rpc Hello(HelloReq) returns (HelloResp);
}
message HelloReq {
string subject = 1;
}
message HelloResp {
string text = 1;
}
服务器实现:
type HelloWorldServer struct{}
func (s *HelloWorldServer) Hello(ctx context.Context, req *pb.HelloReq) (*pb.HelloResp, error) {
return &pb.HelloResp{Text: "Hello " + req.Subject}, nil
}
我尝试了
var Once sync.Once
const bufSize = 1024 * 1024
var listener *bufconn.Listener
func InitTestServer(t *testing.T) *gomock.Controller {
Once.Do(func(){
listener = bufconn.Listen(bufSize)
server := &server.HelloWorldServer{}
twirpHandler := pb.NewHelloWorldServer(server, nil)
mux := http.NewServeMux()
mux.Handle(twirpHandler.PathPrefix(), twirpHandler)
httpServer := http.Server{
Handler: mux,
}
go func() {
if err := httpServer.Serve(listener); err != nil {
if err != http.ErrServerClosed {
log.Fatalln("Failed to start http listener", "error", err)
}
}
}()
})
ctrl := gomock.NewController(t)
return ctrl
}
func bufDialer(context.Context, string) (net.Conn, error) {
return listener.Dial()
}
func TestCreate(t *testing.T) {
//ctrl := InitTestServer(t)
InitTestServer(t)
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithInsecure(), grpc.WithContextDialer(bufDialer))
// conn is of type *ClientConn
if err != nil {
t.Fatalf("Failed to dial bufnet: %v", err)
}
defer conn.Close()
//NewHelloWorldJSONClient accepts only HTTPClient
client := pb.NewHelloWorldJSONClient(conn)
response, err := client.Hello(ctx, &pb.HelloReq{
Subject: "sample",
})
t.Log(response, err)
}
有什么方法可以将一种转换成另一种,或者有什么方法可以测试 Twirp RPC?
您可以使用 net/http/httptest
完成此类测试。
- 使用
pb.NewHelloWorldServer
创建处理程序并为其提供服务器实现结构。 - 使用处理程序创建
httptest.NewServer
。 - 在
pb.NewHelloWorldJSONClient
(或 protobuf,或两者)中使用 httptest 服务器的.URL
。
举个简单的例子:
package main
import (
"context"
"net/http"
"net/http/httptest"
"testing"
pb "github.com/3ventic/twirphelloworld/rpc"
)
// InitTestServer initializes a test server for HelloWorld and returns its address
func InitTestServer() string {
handler := pb.NewHelloWorldServer(&HelloWorldServer{})
server := httptest.NewServer(handler)
return server.URL
}
func TestHello(t *testing.T) {
url := InitTestServer()
clients := map[string]pb.HelloWorld{
"json": pb.NewHelloWorldJSONClient(url, http.DefaultClient),
"pb": pb.NewHelloWorldProtobufClient(url, http.DefaultClient),
}
for typ, client := range clients {
t.Run(typ, func(t *testing.T) {
ctx := context.Background()
result, err := client.Hello(ctx, &pb.HelloReq{
Subject: "test",
})
if err != nil {
t.Error(err)
t.FailNow()
}
if result.Text != "Hello test" {
t.Errorf("result didn't match 'Hello test', was '%s'", result.Text)
}
})
}
}