github.com/openfga/openfga@v1.5.4-rc1/pkg/middleware/recovery/recovery_test.go (about)

     1  package recovery
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"testing"
     9  
    10  	grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
    11  	"github.com/stretchr/testify/require"
    12  	"go.uber.org/goleak"
    13  	"google.golang.org/grpc"
    14  	"google.golang.org/grpc/codes"
    15  	"google.golang.org/grpc/credentials/insecure"
    16  	"google.golang.org/grpc/status"
    17  	"google.golang.org/grpc/test/bufconn"
    18  
    19  	openfgav1 "github.com/openfga/api/proto/openfga/v1"
    20  
    21  	"github.com/openfga/openfga/pkg/logger"
    22  )
    23  
    24  func TestPanic(t *testing.T) {
    25  	panicHandlerFunc := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    26  		panic("Unexpected error!")
    27  	})
    28  
    29  	handler := HTTPPanicRecoveryHandler(panicHandlerFunc, logger.MustNewLogger("text", "info", "unix"))
    30  
    31  	req, err := http.NewRequest(http.MethodGet, "/", nil)
    32  	require.NoError(t, err)
    33  
    34  	resp := httptest.NewRecorder()
    35  	require.NotPanics(t, func() {
    36  		handler.ServeHTTP(resp, req)
    37  	})
    38  
    39  	require.Equal(t, http.StatusInternalServerError, resp.Code)
    40  }
    41  
    42  func TestUnaryPanicInterceptor(t *testing.T) {
    43  	listner := bufconn.Listen(1024 * 1024)
    44  	t.Cleanup(func() {
    45  		listner.Close()
    46  		goleak.VerifyNone(t)
    47  	})
    48  
    49  	serverOpts := []grpc.ServerOption{
    50  		grpc.ChainUnaryInterceptor(
    51  			[]grpc.UnaryServerInterceptor{
    52  				grpc_recovery.UnaryServerInterceptor(
    53  					grpc_recovery.WithRecoveryHandlerContext(
    54  						PanicRecoveryHandler(logger.MustNewLogger("text", "info", "unix")),
    55  					),
    56  				),
    57  			}...,
    58  		),
    59  	}
    60  
    61  	srv := grpc.NewServer(serverOpts...)
    62  	t.Cleanup(srv.Stop)
    63  
    64  	openfgav1.RegisterOpenFGAServiceServer(srv, &unimplementedOpenFGAServiceServer{})
    65  
    66  	go func() {
    67  		err := srv.Serve(listner)
    68  		if err != nil {
    69  			t.Fail()
    70  		}
    71  	}()
    72  
    73  	dialer := func(context.Context, string) (net.Conn, error) {
    74  		return listner.Dial()
    75  	}
    76  
    77  	ctx, cancel := context.WithCancel(context.Background())
    78  	t.Cleanup(cancel)
    79  
    80  	opts := []grpc.DialOption{
    81  		grpc.WithContextDialer(dialer),
    82  		grpc.WithTransportCredentials(insecure.NewCredentials())}
    83  
    84  	conn, err := grpc.DialContext(ctx, "", opts...)
    85  	require.NoError(t, err)
    86  
    87  	t.Cleanup(func() {
    88  		conn.Close()
    89  	})
    90  
    91  	cli := openfgav1.NewOpenFGAServiceClient(conn)
    92  
    93  	_, err = cli.Check(ctx, &openfgav1.CheckRequest{})
    94  	st, ok := status.FromError(err)
    95  	require.True(t, ok)
    96  
    97  	require.Equal(t, codes.Internal, st.Code())
    98  }
    99  
   100  func TestStreamPanicInterceptor(t *testing.T) {
   101  	listner := bufconn.Listen(1024 * 1024)
   102  	t.Cleanup(func() {
   103  		listner.Close()
   104  	})
   105  
   106  	serverOpts := []grpc.ServerOption{
   107  		grpc.ChainStreamInterceptor(
   108  			[]grpc.StreamServerInterceptor{
   109  				grpc_recovery.StreamServerInterceptor(
   110  					grpc_recovery.WithRecoveryHandlerContext(
   111  						PanicRecoveryHandler(logger.MustNewLogger("text", "info", "unix")),
   112  					),
   113  				)}...,
   114  		),
   115  	}
   116  
   117  	srv := grpc.NewServer(serverOpts...)
   118  	t.Cleanup(srv.Stop)
   119  
   120  	openfgav1.RegisterOpenFGAServiceServer(srv, &unimplementedOpenFGAServiceServer{})
   121  
   122  	go func() {
   123  		_ = srv.Serve(listner)
   124  	}()
   125  
   126  	dialer := func(context.Context, string) (net.Conn, error) {
   127  		return listner.Dial()
   128  	}
   129  
   130  	ctx, cancel := context.WithCancel(context.Background())
   131  	t.Cleanup(cancel)
   132  
   133  	opts := []grpc.DialOption{
   134  		grpc.WithContextDialer(dialer),
   135  		grpc.WithTransportCredentials(insecure.NewCredentials())}
   136  
   137  	conn, err := grpc.DialContext(ctx, "", opts...)
   138  	require.NoError(t, err)
   139  
   140  	cli := openfgav1.NewOpenFGAServiceClient(conn)
   141  	stream, err := cli.StreamedListObjects(ctx, &openfgav1.StreamedListObjectsRequest{})
   142  	require.NoError(t, err)
   143  
   144  	_, err = stream.Recv()
   145  	st, ok := status.FromError(err)
   146  	require.True(t, ok)
   147  
   148  	require.Equal(t, codes.Internal, st.Code())
   149  }
   150  
   151  type unimplementedOpenFGAServiceServer struct {
   152  	openfgav1.UnimplementedOpenFGAServiceServer
   153  }
   154  
   155  func (unimplementedOpenFGAServiceServer) Check(context.Context, *openfgav1.CheckRequest) (*openfgav1.CheckResponse, error) {
   156  	panic("Unexpected error!")
   157  }
   158  
   159  func (unimplementedOpenFGAServiceServer) StreamedListObjects(m *openfgav1.StreamedListObjectsRequest, stream openfgav1.OpenFGAService_StreamedListObjectsServer) error {
   160  	_ = stream.RecvMsg(m)
   161  
   162  	panic("Unexpected error!")
   163  }