Go gRPC 服务器使集成测试失败
Go gRPC server make integration tests fail
我最近又开始玩go了,我现在的任务是实现一个服务(在k8s上会运行)作为gRPC服务器。
根据要求,目前,为了满足 k8s 上的 readinessProbe,我需要为我的服务实现一个健康检查端点,并且应该对此进行测试:我所做的是:
func main() {
server := startHTTPServer()
defer server.Close()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
<-c
log.Println("Stopped")
}
func startHTTPServer() *http.Server {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
server := &http.Server{
Addr: net.JoinHostPort("", strconv.Itoa(livelinessPort)),
}
go server.ListenAndServe()
return server
}
我是这样测试的,遵循this article:
func TestMain(m *testing.M) {
flag.Parse()
wg := setup()
result := m.Run()
shutdown(wg)
os.Exit(result)
}
func shutdown(wg *sync.WaitGroup) {
syscall.Kill(syscall.Getpid(), syscall.SIGINT)
wg.Wait()
}
func setup() *sync.WaitGroup{
os.Setenv("APP_ENV", EnvTest)
wg := &sync.WaitGroup{}
startMainProcess(wg)
return wg
}
func startMainProcess(wg *sync.WaitGroup) {
go func() {
wg.Add(1)
defer wg.Done()
main()
}()
}
func TestK8SHealth(t *testing.T) {
res, err := http.Get("http://:8080/")
if err != nil {
t.Errorf("Unexpected API error: %s", err)
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
t.Errorf("Unexpected status code: %d", res.StatusCode)
return
}
}
到目前为止一切顺利:
$ go test
PASS
2018/08/13 09:23:16 Stopped
ok github.com/... 0.015s
问题是当我尝试在 gPRC go examples 之后在主应用程序中添加 gRPC 服务器时。我已将其添加到我的主文件
func main() {
[...]
startChecksServiceServer()
[...]
}
func startChecksServiceServer() *grpc.Server {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", serverPort))
if err != nil {
log.Fatalf("Starting gPRC server error: failed to listen port %d: %v", serverPort, err)
}
grpcServer := grpc.NewServer()
pb.RegisterChecksServiceServer(grpcServer, &checksServiceServer{})
grpcServer.Serve(lis)
log.Println("Started grpc server")
return grpcServer
}
但是现在我运行测试的时候,实际测试是运行,发送中断信号的时候失败了
$ go test
PASS
signal: interrupt
FAIL github.com/... 0.016s
我做了一些测试,这不取决于实际测试(因为它通过了一个测试函数,只是 return
,并且它在使用 goLand 运行 测试套件时工作:
GOROOT=/usr/local/go #gosetup
GOPATH=/Users/marco/Documents/projects/go #gosetup
/usr/local/go/bin/go test -c -i -o /private/var/folders/jh/znhv9f090yb7y390dckb23s00000gn/T/[...] #gosetup
/usr/local/go/bin/go tool test2json -t /private/var/folders/jh/znhv9f090yb7y390dckb23s00000gn/T/[...] -test.v -test.run
^TestK8SHealth$ #gosetup
=== RUN TestK8SHealth
--- PASS: TestK8SHealth (0.00s)
PASS
Process finished with exit code 1
--- 编辑
我发现问题出在监听器周围。在主函数中有:
func main() {
net.Listen("tcp", fmt.Sprintf(":%d", serverPort))
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
<-c
log.Println("Stopped")
}
和只有 return 的测试(与前一个相同的设置)将导致测试失败:
$ go test -v
=== RUN Test2
--- PASS: Test2 (0.00s)
PASS
signal: interrupt
FAIL github.com/[...] 0.014s
grpcServer.Serve(lis)
是阻塞调用。所以就像你对 HTTP 服务器 go server.ListenAndServe()
所做的那样,你需要在 goroutine 中 运行 它。你能试试 go grpcServer.Serve(lis)
是否能让测试通过吗?
我不确定你的新 EDIT 表明问题出在听众身上。您可以检查 net.Listen("tcp", fmt.Sprintf(":%d", serverPort))
returns 或 blocks.
我最近又开始玩go了,我现在的任务是实现一个服务(在k8s上会运行)作为gRPC服务器。
根据要求,目前,为了满足 k8s 上的 readinessProbe,我需要为我的服务实现一个健康检查端点,并且应该对此进行测试:我所做的是:
func main() {
server := startHTTPServer()
defer server.Close()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
<-c
log.Println("Stopped")
}
func startHTTPServer() *http.Server {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
server := &http.Server{
Addr: net.JoinHostPort("", strconv.Itoa(livelinessPort)),
}
go server.ListenAndServe()
return server
}
我是这样测试的,遵循this article:
func TestMain(m *testing.M) {
flag.Parse()
wg := setup()
result := m.Run()
shutdown(wg)
os.Exit(result)
}
func shutdown(wg *sync.WaitGroup) {
syscall.Kill(syscall.Getpid(), syscall.SIGINT)
wg.Wait()
}
func setup() *sync.WaitGroup{
os.Setenv("APP_ENV", EnvTest)
wg := &sync.WaitGroup{}
startMainProcess(wg)
return wg
}
func startMainProcess(wg *sync.WaitGroup) {
go func() {
wg.Add(1)
defer wg.Done()
main()
}()
}
func TestK8SHealth(t *testing.T) {
res, err := http.Get("http://:8080/")
if err != nil {
t.Errorf("Unexpected API error: %s", err)
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
t.Errorf("Unexpected status code: %d", res.StatusCode)
return
}
}
到目前为止一切顺利:
$ go test
PASS
2018/08/13 09:23:16 Stopped
ok github.com/... 0.015s
问题是当我尝试在 gPRC go examples 之后在主应用程序中添加 gRPC 服务器时。我已将其添加到我的主文件
func main() {
[...]
startChecksServiceServer()
[...]
}
func startChecksServiceServer() *grpc.Server {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", serverPort))
if err != nil {
log.Fatalf("Starting gPRC server error: failed to listen port %d: %v", serverPort, err)
}
grpcServer := grpc.NewServer()
pb.RegisterChecksServiceServer(grpcServer, &checksServiceServer{})
grpcServer.Serve(lis)
log.Println("Started grpc server")
return grpcServer
}
但是现在我运行测试的时候,实际测试是运行,发送中断信号的时候失败了
$ go test
PASS
signal: interrupt
FAIL github.com/... 0.016s
我做了一些测试,这不取决于实际测试(因为它通过了一个测试函数,只是 return
,并且它在使用 goLand 运行 测试套件时工作:
GOROOT=/usr/local/go #gosetup
GOPATH=/Users/marco/Documents/projects/go #gosetup
/usr/local/go/bin/go test -c -i -o /private/var/folders/jh/znhv9f090yb7y390dckb23s00000gn/T/[...] #gosetup
/usr/local/go/bin/go tool test2json -t /private/var/folders/jh/znhv9f090yb7y390dckb23s00000gn/T/[...] -test.v -test.run
^TestK8SHealth$ #gosetup
=== RUN TestK8SHealth
--- PASS: TestK8SHealth (0.00s)
PASS
Process finished with exit code 1
--- 编辑
我发现问题出在监听器周围。在主函数中有:
func main() {
net.Listen("tcp", fmt.Sprintf(":%d", serverPort))
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
<-c
log.Println("Stopped")
}
和只有 return 的测试(与前一个相同的设置)将导致测试失败:
$ go test -v
=== RUN Test2
--- PASS: Test2 (0.00s)
PASS
signal: interrupt
FAIL github.com/[...] 0.014s
grpcServer.Serve(lis)
是阻塞调用。所以就像你对 HTTP 服务器 go server.ListenAndServe()
所做的那样,你需要在 goroutine 中 运行 它。你能试试 go grpcServer.Serve(lis)
是否能让测试通过吗?
我不确定你的新 EDIT 表明问题出在听众身上。您可以检查 net.Listen("tcp", fmt.Sprintf(":%d", serverPort))
returns 或 blocks.