goyave.dev/goyave/v5@v5.0.0-rc9.0.20240517145003-d3f977d0b9f3/status_handler_test.go (about)

     1  package goyave
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	"goyave.dev/goyave/v5/config"
    13  	"goyave.dev/goyave/v5/slog"
    14  	"goyave.dev/goyave/v5/util/errors"
    15  	"goyave.dev/goyave/v5/validation"
    16  )
    17  
    18  func prepareStatusHandlerTest() (*Request, *Response, *httptest.ResponseRecorder) {
    19  	server, err := New(Options{Config: config.LoadDefault()})
    20  	if err != nil {
    21  		panic(err)
    22  	}
    23  	httpReq := httptest.NewRequest(http.MethodGet, "/test", nil)
    24  	req := NewRequest(httpReq)
    25  	recorder := httptest.NewRecorder()
    26  	resp := NewResponse(server, req, recorder)
    27  	return req, resp, recorder
    28  }
    29  
    30  func TestPanicStatusHandler(t *testing.T) {
    31  	t.Run("no_debug", func(t *testing.T) {
    32  		req, resp, recorder := prepareStatusHandlerTest()
    33  		resp.server.config.Set("app.debug", false)
    34  		handler := &PanicStatusHandler{}
    35  		handler.Init(resp.server)
    36  
    37  		resp.err = errors.New("test error").(*errors.Error)
    38  		handler.Handle(resp, req)
    39  		res := recorder.Result()
    40  		body, err := io.ReadAll(res.Body)
    41  		assert.NoError(t, res.Body.Close())
    42  		require.NoError(t, err)
    43  
    44  		assert.Equal(t, "{\"error\":\"Internal Server Error\"}\n", string(body))
    45  	})
    46  
    47  	t.Run("debug", func(t *testing.T) {
    48  		req, resp, recorder := prepareStatusHandlerTest()
    49  		resp.server.config.Set("app.debug", true)
    50  		logBuffer := &bytes.Buffer{}
    51  		resp.server.Logger = slog.New(slog.NewHandler(false, logBuffer))
    52  		handler := &PanicStatusHandler{}
    53  		handler.Init(resp.server)
    54  
    55  		resp.err = errors.New("test error").(*errors.Error)
    56  		handler.Handle(resp, req)
    57  		res := recorder.Result()
    58  		body, err := io.ReadAll(res.Body)
    59  		assert.NoError(t, res.Body.Close())
    60  		require.NoError(t, err)
    61  
    62  		assert.Equal(t, "{\"error\":\"test error\"}\n", string(body))
    63  
    64  		// Error and stacktrace already printed by the recovery middleware or `response.Error`
    65  		// (those are not executed in this test, thus leaving the log buffer empty)
    66  		assert.Empty(t, logBuffer.String())
    67  	})
    68  
    69  	t.Run("nil_error", func(t *testing.T) {
    70  		req, resp, recorder := prepareStatusHandlerTest()
    71  		resp.server.config.Set("app.debug", true)
    72  		logBuffer := &bytes.Buffer{}
    73  		resp.server.Logger = slog.New(slog.NewHandler(false, logBuffer))
    74  		handler := &PanicStatusHandler{}
    75  		handler.Init(resp.server)
    76  
    77  		handler.Handle(resp, req)
    78  		res := recorder.Result()
    79  		body, err := io.ReadAll(res.Body)
    80  		assert.NoError(t, res.Body.Close())
    81  		require.NoError(t, err)
    82  
    83  		assert.Equal(t, "{\"error\":null}\n", string(body))
    84  
    85  		// Error and stacktrace are not printed to console because recovery middleware
    86  		// is not executed (no error raised, we just set the response status to 500 for example)
    87  		assert.Empty(t, logBuffer.String())
    88  	})
    89  }
    90  
    91  func TestErrorStatusHandler(t *testing.T) {
    92  	req, resp, recorder := prepareStatusHandlerTest()
    93  	handler := &ErrorStatusHandler{}
    94  	handler.Init(resp.server)
    95  
    96  	resp.Status(http.StatusNotFound)
    97  
    98  	handler.Handle(resp, req)
    99  
   100  	res := recorder.Result()
   101  	body, err := io.ReadAll(res.Body)
   102  	assert.NoError(t, res.Body.Close())
   103  	require.NoError(t, err)
   104  
   105  	assert.Equal(t, "{\"error\":\"Not Found\"}\n", string(body))
   106  }
   107  
   108  func TestValidationStatusHandler(t *testing.T) {
   109  	req, resp, recorder := prepareStatusHandlerTest()
   110  	handler := &ValidationStatusHandler{}
   111  	handler.Init(resp.server)
   112  
   113  	req.Extra[ExtraValidationError{}] = &validation.Errors{
   114  		Errors: []string{"The body is required"},
   115  		Fields: validation.FieldsErrors{
   116  			"field": &validation.Errors{Errors: []string{"The field is required"}},
   117  		},
   118  	}
   119  	req.Extra[ExtraQueryValidationError{}] = &validation.Errors{
   120  		Fields: validation.FieldsErrors{
   121  			"query": &validation.Errors{Errors: []string{"The query is required"}},
   122  		},
   123  	}
   124  
   125  	handler.Handle(resp, req)
   126  
   127  	res := recorder.Result()
   128  	body, err := io.ReadAll(res.Body)
   129  	assert.NoError(t, res.Body.Close())
   130  	require.NoError(t, err)
   131  
   132  	assert.Equal(t, "{\"error\":{\"body\":{\"fields\":{\"field\":{\"errors\":[\"The field is required\"]}},\"errors\":[\"The body is required\"]},\"query\":{\"fields\":{\"query\":{\"errors\":[\"The query is required\"]}}}}}\n", string(body))
   133  }