grpc测试代码退出1,显示’rpc错误:代码=未实现,描述=方法Hello未实现’。

huangapple go评论85阅读模式
英文:

grpc testing code exit 1 with 'rpc error: code = Unimplemented desc = method Hello not implemented'

问题

环境

go version go1.17.4 linux/amd64

libprotoc 3.6.1

问题

我正在测试使用Go实现的gRPC服务器和客户端。
首先,我制作了proto定义,并通过protoc命令生成了pb代码。
我参考了这个解决方案
下面的错误是通过最小的代码来重现我的错误。

错误

$ go test
--- FAIL: TestHello (0.00s)
    main_test.go:49: failed to Hello: rpc error: code = Unimplemented desc = method Hello not implemented
FAIL
exit status 1
FAIL    github.com/Asuha-a/test/test    0.003s

代码

hello.proto

syntax = "proto3";

option go_package = "github.com/Asuha-a/test/pb";

package hello;

service Hello {
  rpc Hello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string foo = 1;
}

message HelloReply {
  string bar = 1;
}

main_test.go

package hello_test

import (
	"context"
	"log"
	"net"
	"testing"

	"github.com/Asuha-a/test/pb"
	"google.golang.org/grpc"
	"google.golang.org/grpc/test/bufconn"
)

type server struct {
	pb.UnimplementedHelloServer
}

const bufSize = 1024 * 1024

var lis *bufconn.Listener

func init() {
	lis = bufconn.Listen(bufSize)
	s := grpc.NewServer()
	pb.RegisterHelloServer(s, &server{})
	go func() {
		if err := s.Serve(lis); err != nil {
			log.Fatalf("server exited with error: %v", err)
		}
	}()
}

func bufDialer(context.Context, string) (net.Conn, error) {
	return lis.Dial()
}

func TestHello(t *testing.T) {
	ctx := context.Background()
	conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
	if err != nil {
		t.Fatalf("failed to dial bufnet: %v", err)
	}
	defer conn.Close()
	client := pb.NewHelloClient(conn)
	r, err := client.Hello(ctx, &pb.HelloRequest{
		Foo: "foo",
	})
	if err != nil {
		t.Fatalf("failed to Hello: %v", err) //49th line prints the error
	}
	log.Println(r)
}
英文:

Environment

go version go1.17.4 linux/amd64

libprotoc 3.6.1

Problem

I'm testing grpc server and client implemented by Go.
First, I made proto definition and generate pb codes by protoc command.
I referred this solution.
Following the error is printed by minimum codes to reproduce my error.

Error

$ go test
--- FAIL: TestHello (0.00s)
    main_test.go:49: failed to Hello: rpc error: code = Unimplemented desc = method Hello not implemented
FAIL
exit status 1
FAIL    github.com/Asuha-a/test/test    0.003s

Code

hello.proto

syntax = "proto3";

option go_package = "github.com/Asuha-a/test/pb";

package hello;

service Hello {
  rpc Hello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string foo = 1;
}

message HelloReply {
  string bar = 1;
}

main_test.go

package hello_test

import (
	"context"
	"log"
	"net"
	"testing"

	"github.com/Asuha-a/test/pb"
	"google.golang.org/grpc"
	"google.golang.org/grpc/test/bufconn"
)

type server struct {
	pb.UnimplementedHelloServer
}

const bufSize = 1024 * 1024

var lis *bufconn.Listener

func init() {
	lis = bufconn.Listen(bufSize)
	s := grpc.NewServer()
	pb.RegisterHelloServer(s, &server{})
	go func() {
		if err := s.Serve(lis); err != nil {
			log.Fatalf("server exited with error: %v", err)
		}
	}()
}

func bufDialer(context.Context, string) (net.Conn, error) {
	return lis.Dial()
}

func TestHello(t *testing.T) {
	ctx := context.Background()
	conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
	if err != nil {
		t.Fatalf("failed to dial bufnet: %v", err)
	}
	defer conn.Close()
	client := pb.NewHelloClient(conn)
	r, err := client.Hello(ctx, &pb.HelloRequest{
		Foo: "foo",
	})
	if err != nil {
		t.Fatalf("failed to Hello: %v", err) //49th line prints the error
	}
	log.Println(r)
}

答案1

得分: 3

在你的测试中,你使用 server 结构体调用了 pb.RegisterHelloServer(s, &server{})。然而,这个结构体只嵌入了 pb.UnimplementedHelloServer,并且没有声明任何方法。因此,当调用它的任何 RPC 时,你只能得到 codes.Unimplemented 的返回值。

你需要在 server 结构体上实现 Hello RPC:

func (s *server) Hello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
    return &pb.HelloReply{}, nil
}

**注意:**嵌入 pb.UnimplementedHelloServer 可以使 gRPC 服务器实现向前兼容,但会牺牲编译时检查的功能。如果要放弃向前兼容性并在编译时捕获这些错误,可以改为嵌入 pb.UnsafeHelloServer

英文:

In your test you are calling pb.RegisterHelloServer(s, &server{}) using the server struct. However this struct only embeds pb.UnimplementedHelloServer and declares no methods. Hence, you can only get codes.Unimplemented back when calling any of its RPCs.

You have to implement the Hello rpc on the server struct:

func (s *server) Hello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{}, nil
}

Note: embedding pb.UnimplementedHelloServer makes the gRPC server implementations forward compatible at the expense of compile-time checks. To forgo forward compatibility and catch these errors at compile time, you can embed instead pb.UnsafeHelloServer.

huangapple
  • 本文由 发表于 2021年12月10日 21:45:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/70305459.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定