goyave.dev/goyave/v5@v5.0.0-rc9.0.20240517145003-d3f977d0b9f3/middleware/parse/parse_test.go (about)

     1  package parse
     2  
     3  import (
     4  	"bytes"
     5  	"mime/multipart"
     6  	"net/http"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	"goyave.dev/goyave/v5"
    13  	"goyave.dev/goyave/v5/config"
    14  	"goyave.dev/goyave/v5/util/fsutil"
    15  	"goyave.dev/goyave/v5/util/fsutil/osfs"
    16  	"goyave.dev/goyave/v5/util/testutil"
    17  )
    18  
    19  func TestParseMiddleware(t *testing.T) {
    20  
    21  	server := testutil.NewTestServerWithOptions(t, goyave.Options{Config: config.LoadDefault()})
    22  
    23  	t.Run("Max Upload Size", func(t *testing.T) {
    24  		m := &Middleware{}
    25  		m.Init(server.Server)
    26  		assert.InEpsilon(t, 10.0, m.getMaxUploadSize(), 0) // Default
    27  		m.MaxUploadSize = 2.3
    28  		assert.InEpsilon(t, 2.3, m.getMaxUploadSize(), 0)
    29  
    30  		m = &Middleware{
    31  			MaxUploadSize: 2.3,
    32  		}
    33  		m.Init(server.Server)
    34  		assert.InEpsilon(t, 2.3, m.getMaxUploadSize(), 0)
    35  	})
    36  
    37  	t.Run("Parse Query", func(t *testing.T) {
    38  		request := testutil.NewTestRequest(http.MethodGet, "/parse?a=b&c=d&array=1&array=2", nil)
    39  
    40  		result := server.TestMiddleware(&Middleware{}, request, func(_ *goyave.Response, req *goyave.Request) {
    41  			expected := map[string]any{
    42  				"a":     "b",
    43  				"c":     "d",
    44  				"array": []string{"1", "2"},
    45  			}
    46  			assert.Equal(t, expected, req.Query)
    47  		})
    48  		assert.NoError(t, result.Body.Close())
    49  	})
    50  
    51  	t.Run("Parse Query Error", func(t *testing.T) {
    52  		request := testutil.NewTestRequest(http.MethodGet, "/parse?inv;alid", nil)
    53  
    54  		result := server.TestMiddleware(&Middleware{}, request, func(_ *goyave.Response, req *goyave.Request) {
    55  			assert.Equal(t, map[string]any{}, req.Query)
    56  		})
    57  		assert.NoError(t, result.Body.Close())
    58  		assert.Equal(t, http.StatusBadRequest, result.StatusCode)
    59  	})
    60  
    61  	t.Run("Entity Too Large", func(t *testing.T) {
    62  		request := testutil.NewTestRequest(http.MethodPost, "/parse", strings.NewReader(strings.Repeat("a", 1024*1024)))
    63  		request.Header().Set("Content-Type", "application/octet-stream")
    64  
    65  		result := server.TestMiddleware(&Middleware{MaxUploadSize: 0.01}, request, func(_ *goyave.Response, _ *goyave.Request) {
    66  			assert.Fail(t, "Middleware should not pass")
    67  		})
    68  		assert.NoError(t, result.Body.Close())
    69  		assert.Equal(t, http.StatusRequestEntityTooLarge, result.StatusCode)
    70  	})
    71  
    72  	t.Run("JSON", func(t *testing.T) {
    73  		data := map[string]any{
    74  			"a": "b",
    75  			"c": "d",
    76  			"e": map[string]any{
    77  				"f": "g",
    78  			},
    79  			"h": []string{"i", "j"},
    80  		}
    81  
    82  		request := testutil.NewTestRequest(http.MethodPost, "/parse", testutil.ToJSON(data))
    83  		request.Header().Set("Content-Type", "application/json")
    84  
    85  		result := server.TestMiddleware(&Middleware{}, request, func(resp *goyave.Response, req *goyave.Request) {
    86  			expected := map[string]any{
    87  				"a": "b",
    88  				"c": "d",
    89  				"e": map[string]any{
    90  					"f": "g",
    91  				},
    92  				"h": []any{"i", "j"},
    93  			}
    94  			assert.Equal(t, expected, req.Data)
    95  			resp.Status(http.StatusOK)
    96  		})
    97  
    98  		assert.NoError(t, result.Body.Close())
    99  		assert.Equal(t, http.StatusOK, result.StatusCode)
   100  	})
   101  
   102  	t.Run("JSON Invalid", func(t *testing.T) {
   103  		request := testutil.NewTestRequest(http.MethodPost, "/parse", bytes.NewBuffer([]byte("{\"unclosed\"")))
   104  		request.Header().Set("Content-Type", "application/json")
   105  
   106  		result := server.TestMiddleware(&Middleware{MaxUploadSize: 0.01}, request, func(_ *goyave.Response, _ *goyave.Request) {
   107  			assert.Fail(t, "Middleware should not pass")
   108  		})
   109  		assert.NoError(t, result.Body.Close())
   110  		assert.Equal(t, http.StatusBadRequest, result.StatusCode)
   111  	})
   112  
   113  	t.Run("Multipart", func(t *testing.T) {
   114  		body := &bytes.Buffer{}
   115  		writer := multipart.NewWriter(body)
   116  		require.NoError(t, testutil.WriteMultipartFile(writer, &osfs.FS{}, "../../resources/img/logo/goyave_16.png", "profile_picture", "goyave_16.png"))
   117  		require.NoError(t, writer.WriteField("email", "johndoe@example.org"))
   118  
   119  		request := testutil.NewTestRequest(http.MethodPost, "/parse", body)
   120  		request.Header().Set("Content-Type", writer.FormDataContentType())
   121  
   122  		require.NoError(t, writer.Close())
   123  
   124  		result := server.TestMiddleware(&Middleware{}, request, func(resp *goyave.Response, req *goyave.Request) {
   125  			data, ok := req.Data.(map[string]any)
   126  			if !assert.True(t, ok) {
   127  				return
   128  			}
   129  			assert.Equal(t, "johndoe@example.org", data["email"])
   130  
   131  			picture, ok := data["profile_picture"].([]fsutil.File)
   132  			if !assert.True(t, ok) {
   133  				return
   134  			}
   135  
   136  			if !assert.Len(t, picture, 1) {
   137  				return
   138  			}
   139  			assert.Equal(t, "image/png", picture[0].MIMEType)
   140  			assert.Equal(t, "goyave_16.png", picture[0].Header.Filename)
   141  			assert.Equal(t, int64(716), picture[0].Header.Size)
   142  
   143  			resp.Status(http.StatusOK)
   144  		})
   145  
   146  		assert.NoError(t, result.Body.Close())
   147  		assert.Equal(t, http.StatusOK, result.StatusCode)
   148  	})
   149  
   150  	t.Run("Form URL-encoded", func(t *testing.T) {
   151  		data := "a=b&c=d&h=i&h=j"
   152  
   153  		request := testutil.NewTestRequest(http.MethodPost, "/parse", strings.NewReader(data))
   154  		request.Header().Set("Content-Type", "application/x-www-form-urlencoded; param=value")
   155  
   156  		result := server.TestMiddleware(&Middleware{}, request, func(resp *goyave.Response, req *goyave.Request) {
   157  			expected := map[string]any{
   158  				"a": "b",
   159  				"c": "d",
   160  				"h": []string{"i", "j"},
   161  			}
   162  			assert.Equal(t, expected, req.Data)
   163  			resp.Status(http.StatusOK)
   164  		})
   165  
   166  		assert.NoError(t, result.Body.Close())
   167  		assert.Equal(t, http.StatusOK, result.StatusCode)
   168  	})
   169  
   170  	t.Run("Body already parsed", func(t *testing.T) {
   171  		data := map[string]any{
   172  			"a": "b",
   173  			"c": "d",
   174  			"e": map[string]any{
   175  				"f": "g",
   176  			},
   177  			"h": []string{"i", "j"},
   178  		}
   179  		request := testutil.NewTestRequest(http.MethodPost, "/parse?a=b&c=d&array=1&array=2", testutil.ToJSON(data))
   180  		request.Data = map[string]any{"a": "b"}
   181  
   182  		result := server.TestMiddleware(&Middleware{}, request, func(_ *goyave.Response, req *goyave.Request) {
   183  			expectedQuery := map[string]any{
   184  				"a":     "b",
   185  				"c":     "d",
   186  				"array": []string{"1", "2"},
   187  			}
   188  			assert.Equal(t, expectedQuery, req.Query) // Query parsed but not body
   189  			assert.Equal(t, map[string]any{"a": "b"}, req.Data)
   190  		})
   191  		assert.NoError(t, result.Body.Close())
   192  	})
   193  }