goyave.dev/goyave/v5@v5.0.0-rc9.0.20240517145003-d3f977d0b9f3/util/testutil/testutil_test.go (about)

     1  package testutil
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"mime/multipart"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"net/textproto"
    10  	"path"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  	"goyave.dev/goyave/v5"
    16  	"goyave.dev/goyave/v5/config"
    17  	"goyave.dev/goyave/v5/slog"
    18  	"goyave.dev/goyave/v5/util/fsutil"
    19  	"goyave.dev/goyave/v5/util/fsutil/osfs"
    20  )
    21  
    22  type extraKey struct{}
    23  
    24  type testMiddleware struct {
    25  	goyave.Component
    26  	procedure goyave.Handler
    27  }
    28  
    29  func (m *testMiddleware) Handle(_ goyave.Handler) goyave.Handler {
    30  	return m.procedure
    31  }
    32  
    33  func TestTestServer(t *testing.T) {
    34  
    35  	t.Run("NewTestServer", func(t *testing.T) {
    36  		server := NewTestServer(t, "resources/custom_config.json")
    37  		assert.Equal(t, "value", server.Config().Get("custom-entry"))
    38  		assert.Equal(t, slog.New(slog.NewHandler(true, &LogWriter{t: t})), server.Logger)
    39  	})
    40  
    41  	t.Run("NewTestServerWithOptions", func(t *testing.T) {
    42  		cfg := config.LoadDefault()
    43  		cfg.Set("test-entry", "test-value")
    44  
    45  		server := NewTestServerWithOptions(t, goyave.Options{Config: cfg})
    46  
    47  		assert.NotNil(t, server.Lang)
    48  		assert.Equal(t, "test-value", server.Config().Get("test-entry"))
    49  		assert.Equal(t, slog.New(slog.NewHandler(true, &LogWriter{t: t})), server.Logger)
    50  	})
    51  
    52  	t.Run("NewTestServer_AutoConfig", func(t *testing.T) {
    53  		t.Setenv("GOYAVE_ENV", "test")
    54  		server := NewTestServerWithOptions(t, goyave.Options{})
    55  
    56  		assert.NotNil(t, server.Lang)
    57  		assert.Equal(t, "test-value", server.Config().Get("test-entry"))
    58  
    59  		assert.Panics(t, func() {
    60  			// Config file not found
    61  			t.Setenv("GOYAVE_ENV", "")
    62  			NewTestServerWithOptions(t, goyave.Options{})
    63  		})
    64  	})
    65  
    66  	t.Run("TestRequest", func(t *testing.T) {
    67  		server := NewTestServerWithOptions(t, goyave.Options{Config: config.LoadDefault()})
    68  		server.RegisterRoutes(func(_ *goyave.Server, r *goyave.Router) {
    69  			r.Get("/route", func(resp *goyave.Response, _ *goyave.Request) {
    70  				resp.String(http.StatusOK, "OK")
    71  			})
    72  		})
    73  
    74  		resp := server.TestRequest(httptest.NewRequest(http.MethodGet, "/route", nil))
    75  		assert.Equal(t, http.StatusOK, resp.StatusCode)
    76  		respBody, err := io.ReadAll(resp.Body)
    77  		require.NoError(t, resp.Body.Close())
    78  		require.NoError(t, err)
    79  		assert.Equal(t, "OK", string(respBody))
    80  	})
    81  
    82  	t.Run("TestMiddleware", func(t *testing.T) {
    83  		server := NewTestServerWithOptions(t, goyave.Options{Config: config.LoadDefault()})
    84  
    85  		request := server.NewTestRequest(http.MethodGet, "/route", nil)
    86  		request.Data = map[string]any{"key": "value"}
    87  		request.Extra = map[any]any{extraKey{}: "value"}
    88  		request.Query = map[string]any{"key": "value"}
    89  		request.RouteParams = map[string]string{"key": "value"}
    90  		request.User = map[string]string{"key": "value"}
    91  
    92  		middleware := &testMiddleware{
    93  			procedure: func(resp *goyave.Response, req *goyave.Request) {
    94  				assert.Equal(t, request.Now, req.Now)
    95  				assert.Equal(t, request.Data, req.Data)
    96  				assert.Equal(t, request.Extra, req.Extra)
    97  				assert.Equal(t, request.Lang, req.Lang)
    98  				assert.Equal(t, request.Query, req.Query)
    99  				assert.Equal(t, request.RouteParams, req.RouteParams)
   100  				assert.Equal(t, request.User, req.User)
   101  				resp.String(http.StatusOK, "OK")
   102  			},
   103  		}
   104  
   105  		resp := server.TestMiddleware(middleware, request, func(response *goyave.Response, _ *goyave.Request) {
   106  			response.Status(http.StatusBadRequest)
   107  		})
   108  		assert.Equal(t, http.StatusOK, resp.StatusCode)
   109  		respBody, err := io.ReadAll(resp.Body)
   110  		require.NoError(t, resp.Body.Close())
   111  		require.NoError(t, err)
   112  		assert.Equal(t, "OK", string(respBody))
   113  	})
   114  
   115  	t.Run("NewTestRequest", func(t *testing.T) {
   116  		server := NewTestServerWithOptions(t, goyave.Options{Config: config.LoadDefault()})
   117  		body := bytes.NewBufferString("body")
   118  		req := server.NewTestRequest(http.MethodPost, "/uri", body)
   119  
   120  		assert.Equal(t, http.MethodPost, req.Method())
   121  		assert.Equal(t, "/uri", req.URL().String())
   122  		assert.NotNil(t, req.Extra)
   123  
   124  		b, err := io.ReadAll(req.Body())
   125  		require.NoError(t, err)
   126  		assert.Equal(t, "body", string(b))
   127  		assert.Equal(t, server.Lang.GetDefault(), req.Lang)
   128  	})
   129  
   130  	t.Run("NewTestResponse", func(t *testing.T) {
   131  		server := NewTestServerWithOptions(t, goyave.Options{Config: config.LoadDefault(), Logger: slog.New(slog.NewHandler(false, &bytes.Buffer{}))})
   132  		req := server.NewTestRequest(http.MethodGet, "/uri", nil)
   133  		resp, recorder := server.NewTestResponse(req)
   134  
   135  		resp.String(http.StatusOK, "hello")
   136  		result := recorder.Result()
   137  		b, err := io.ReadAll(result.Body)
   138  		require.NoError(t, result.Body.Close())
   139  		require.NoError(t, err)
   140  		assert.Equal(t, "hello", string(b))
   141  		assert.NotPanics(t, func() {
   142  			// No panics because the server is accessible so the ErrLogger.Println succeeds
   143  			resp.Error(nil)
   144  		})
   145  	})
   146  }
   147  
   148  func TestFindRootDirectory(t *testing.T) {
   149  	dir := FindRootDirectory()
   150  	assert.True(t, fsutil.FileExists(&osfs.FS{}, path.Join(dir, "go.mod")))
   151  }
   152  
   153  func TestNewTestRequest(t *testing.T) {
   154  	body := bytes.NewBufferString("body")
   155  	req := NewTestRequest(http.MethodPost, "/uri", body)
   156  
   157  	assert.Equal(t, http.MethodPost, req.Method())
   158  	assert.Equal(t, "/uri", req.URL().String())
   159  	assert.NotNil(t, req.Extra)
   160  
   161  	b, err := io.ReadAll(req.Body())
   162  	require.NoError(t, err)
   163  	assert.Equal(t, "body", string(b))
   164  
   165  }
   166  
   167  func TestNewTestResponse(t *testing.T) {
   168  	req := NewTestRequest(http.MethodGet, "/uri", nil)
   169  	resp, recorder := NewTestResponse(req)
   170  
   171  	resp.String(http.StatusOK, "hello")
   172  	result := recorder.Result()
   173  	b, err := io.ReadAll(result.Body)
   174  	require.NoError(t, result.Body.Close())
   175  	require.NoError(t, err)
   176  	assert.Equal(t, "hello", string(b))
   177  }
   178  
   179  func TestReadJSONBody(t *testing.T) {
   180  	body := bytes.NewBufferString(`{"key":"value"}`)
   181  	jsonBody, err := ReadJSONBody[map[string]string](body)
   182  	require.NoError(t, err)
   183  	assert.Equal(t, map[string]string{"key": "value"}, jsonBody)
   184  
   185  	jsonBodyError, err := ReadJSONBody[string](body)
   186  	require.Error(t, err)
   187  	assert.Empty(t, jsonBodyError)
   188  }
   189  
   190  func TestWriteMultipartFile(t *testing.T) {
   191  	body := &bytes.Buffer{}
   192  	writer := multipart.NewWriter(body)
   193  	require.NoError(t, WriteMultipartFile(writer, &osfs.FS{}, "../../resources/img/logo/goyave_16.png", "profile_picture", "goyave_16.png"))
   194  	require.NoError(t, writer.Close())
   195  
   196  	req := NewTestRequest(http.MethodPost, "/uri", body)
   197  	req.Header().Set("Content-Type", writer.FormDataContentType())
   198  	require.NoError(t, req.Request().ParseMultipartForm(1024*1024*1024))
   199  
   200  	files := req.Request().MultipartForm.File
   201  	require.Len(t, files, 1)
   202  	require.Contains(t, files, "profile_picture")
   203  
   204  	file := files["profile_picture"]
   205  	require.Len(t, file, 1)
   206  	assert.Equal(t, "goyave_16.png", file[0].Filename)
   207  	assert.Equal(t, int64(716), file[0].Size)
   208  	assert.Equal(t, textproto.MIMEHeader{"Content-Type": []string{"application/octet-stream"}, "Content-Disposition": []string{"form-data; name=\"profile_picture\"; filename=\"goyave_16.png\""}}, file[0].Header)
   209  }
   210  
   211  func TestCreateTestFiles(t *testing.T) {
   212  	files, err := CreateTestFiles(&osfs.FS{}, "../../resources/img/logo/goyave_16.png", "../../resources/test_file.txt")
   213  	require.NoError(t, err)
   214  	require.Len(t, files, 2)
   215  
   216  	assert.Equal(t, "goyave_16.png", files[0].Header.Filename)
   217  	assert.Equal(t, int64(716), files[0].Header.Size)
   218  	assert.Equal(t, textproto.MIMEHeader{"Content-Type": []string{"application/octet-stream"}, "Content-Disposition": []string{"form-data; name=\"file\"; filename=\"goyave_16.png\""}}, files[0].Header.Header)
   219  
   220  	assert.Equal(t, "test_file.txt", files[1].Header.Filename)
   221  	assert.Equal(t, int64(25), files[1].Header.Size)
   222  	assert.Equal(t, textproto.MIMEHeader{"Content-Type": []string{"application/octet-stream"}, "Content-Disposition": []string{"form-data; name=\"file\"; filename=\"test_file.txt\""}}, files[1].Header.Header)
   223  
   224  }
   225  
   226  func TestToJSON(t *testing.T) {
   227  	reader := ToJSON(map[string]any{"key": "value"})
   228  	result, err := io.ReadAll(reader)
   229  	require.NoError(t, err)
   230  	assert.Equal(t, `{"key":"value"}`, string(result))
   231  
   232  	assert.Panics(t, func() {
   233  		ToJSON(make(chan struct{}))
   234  	})
   235  }