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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
// Copyright (c) The go-grpc-middleware Authors.
// Licensed under the Apache License 2.0.
// Copyright 2017 David Ackroyd. All Rights Reserved.
// See LICENSE for licensing terms.
package recovery_test
import (
"context"
"testing"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/testing/testpb"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type recoveryAssertService struct {
testpb.TestServiceServer
}
func (s *recoveryAssertService) Ping(ctx context.Context, ping *testpb.PingRequest) (*testpb.PingResponse, error) {
if ping.Value == "panic" {
panic("very bad thing happened")
}
return s.TestServiceServer.Ping(ctx, ping)
}
func (s *recoveryAssertService) PingList(ping *testpb.PingListRequest, stream testpb.TestService_PingListServer) error {
if ping.Value == "panic" {
panic("very bad thing happened")
}
return s.TestServiceServer.PingList(ping, stream)
}
func TestRecoverySuite(t *testing.T) {
s := &RecoverySuite{
InterceptorTestSuite: &testpb.InterceptorTestSuite{
TestService: &recoveryAssertService{TestServiceServer: &testpb.TestPingService{}},
ServerOpts: []grpc.ServerOption{
grpc.StreamInterceptor(
recovery.StreamServerInterceptor()),
grpc.UnaryInterceptor(
recovery.UnaryServerInterceptor()),
},
},
}
suite.Run(t, s)
}
type RecoverySuite struct {
*testpb.InterceptorTestSuite
}
func (s *RecoverySuite) TestUnary_SuccessfulRequest() {
_, err := s.Client.Ping(s.SimpleCtx(), testpb.GoodPing)
require.NoError(s.T(), err, "no error must occur")
}
func (s *RecoverySuite) TestUnary_PanickingRequest() {
_, err := s.Client.Ping(s.SimpleCtx(), &testpb.PingRequest{Value: "panic"})
require.Error(s.T(), err, "there must be an error")
assert.Equal(s.T(), codes.Unknown, status.Code(err), "must error with unknown")
assert.Contains(s.T(), status.Convert(err).Message(), "panic caught", "must error with message")
assert.Contains(s.T(), status.Convert(err).Message(), "recovery.recoverFrom", "must include stack trace")
}
func (s *RecoverySuite) TestStream_SuccessfulReceive() {
stream, err := s.Client.PingList(s.SimpleCtx(), testpb.GoodPingList)
require.NoError(s.T(), err, "should not fail on establishing the stream")
pong, err := stream.Recv()
require.NoError(s.T(), err, "no error must occur")
require.NotNil(s.T(), pong, "pong must not be nil")
}
func (s *RecoverySuite) TestStream_PanickingReceive() {
stream, err := s.Client.PingList(s.SimpleCtx(), &testpb.PingListRequest{Value: "panic"})
require.NoError(s.T(), err, "should not fail on establishing the stream")
_, err = stream.Recv()
require.Error(s.T(), err, "there must be an error")
assert.Equal(s.T(), codes.Unknown, status.Code(err), "must error with unknown")
assert.Contains(s.T(), status.Convert(err).Message(), "panic caught", "must error with message")
assert.Contains(s.T(), status.Convert(err).Message(), "recovery.recoverFrom", "must include stack trace")
}
func TestRecoveryOverrideSuite(t *testing.T) {
opts := []recovery.Option{
recovery.WithRecoveryHandler(func(p any) (err error) {
return status.Errorf(codes.Unknown, "panic triggered: %v", p)
}),
}
s := &RecoveryOverrideSuite{
InterceptorTestSuite: &testpb.InterceptorTestSuite{
TestService: &recoveryAssertService{TestServiceServer: &testpb.TestPingService{}},
ServerOpts: []grpc.ServerOption{
grpc.StreamInterceptor(
recovery.StreamServerInterceptor(opts...)),
grpc.UnaryInterceptor(
recovery.UnaryServerInterceptor(opts...)),
},
},
}
suite.Run(t, s)
}
type RecoveryOverrideSuite struct {
*testpb.InterceptorTestSuite
}
func (s *RecoveryOverrideSuite) TestUnary_SuccessfulRequest() {
_, err := s.Client.Ping(s.SimpleCtx(), testpb.GoodPing)
require.NoError(s.T(), err, "no error must occur")
}
func (s *RecoveryOverrideSuite) TestUnary_PanickingRequest() {
_, err := s.Client.Ping(s.SimpleCtx(), &testpb.PingRequest{Value: "panic"})
require.Error(s.T(), err, "there must be an error")
assert.Equal(s.T(), codes.Unknown, status.Code(err), "must error with unknown")
assert.Equal(s.T(), "panic triggered: very bad thing happened", status.Convert(err).Message(), "must error with message")
}
func (s *RecoveryOverrideSuite) TestStream_SuccessfulReceive() {
stream, err := s.Client.PingList(s.SimpleCtx(), testpb.GoodPingList)
require.NoError(s.T(), err, "should not fail on establishing the stream")
pong, err := stream.Recv()
require.NoError(s.T(), err, "no error must occur")
require.NotNil(s.T(), pong, "pong must not be nil")
}
func (s *RecoveryOverrideSuite) TestStream_PanickingReceive() {
stream, err := s.Client.PingList(s.SimpleCtx(), &testpb.PingListRequest{Value: "panic"})
require.NoError(s.T(), err, "should not fail on establishing the stream")
_, err = stream.Recv()
require.Error(s.T(), err, "there must be an error")
assert.Equal(s.T(), codes.Unknown, status.Code(err), "must error with unknown")
assert.Equal(s.T(), "panic triggered: very bad thing happened", status.Convert(err).Message(), "must error with message")
}
|