github.com/gofiber/fiber/v2@v2.47.0/app_test.go (about)

     1  // ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
     2  // 🤖 Github Repository: https://github.com/gofiber/fiber
     3  // 📌 API Documentation: https://docs.gofiber.io
     4  
     5  //nolint:bodyclose // Much easier to just ignore memory leaks in tests
     6  package fiber
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"crypto/tls"
    12  	"errors"
    13  	"fmt"
    14  	"io"
    15  	"mime/multipart"
    16  	"net"
    17  	"net/http"
    18  	"net/http/httptest"
    19  	"reflect"
    20  	"regexp"
    21  	"runtime"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/gofiber/fiber/v2/utils"
    27  
    28  	"github.com/valyala/fasthttp"
    29  	"github.com/valyala/fasthttp/fasthttputil"
    30  )
    31  
    32  func testEmptyHandler(_ *Ctx) error {
    33  	return nil
    34  }
    35  
    36  func testStatus200(t *testing.T, app *App, url, method string) {
    37  	t.Helper()
    38  
    39  	req := httptest.NewRequest(method, url, nil)
    40  
    41  	resp, err := app.Test(req)
    42  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    43  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
    44  }
    45  
    46  func testErrorResponse(t *testing.T, err error, resp *http.Response, expectedBodyError string) {
    47  	t.Helper()
    48  
    49  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    50  	utils.AssertEqual(t, 500, resp.StatusCode, "Status code")
    51  
    52  	body, err := io.ReadAll(resp.Body)
    53  	utils.AssertEqual(t, nil, err)
    54  	utils.AssertEqual(t, expectedBodyError, string(body), "Response body")
    55  }
    56  
    57  func Test_App_MethodNotAllowed(t *testing.T) {
    58  	t.Parallel()
    59  	app := New()
    60  
    61  	app.Use(func(c *Ctx) error {
    62  		return c.Next()
    63  	})
    64  
    65  	app.Post("/", testEmptyHandler)
    66  
    67  	app.Options("/", testEmptyHandler)
    68  
    69  	resp, err := app.Test(httptest.NewRequest(MethodPost, "/", nil))
    70  	utils.AssertEqual(t, nil, err)
    71  	utils.AssertEqual(t, 200, resp.StatusCode)
    72  	utils.AssertEqual(t, "", resp.Header.Get(HeaderAllow))
    73  
    74  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/", nil))
    75  	utils.AssertEqual(t, nil, err)
    76  	utils.AssertEqual(t, 405, resp.StatusCode)
    77  	utils.AssertEqual(t, "POST, OPTIONS", resp.Header.Get(HeaderAllow))
    78  
    79  	resp, err = app.Test(httptest.NewRequest(MethodPatch, "/", nil))
    80  	utils.AssertEqual(t, nil, err)
    81  	utils.AssertEqual(t, 405, resp.StatusCode)
    82  	utils.AssertEqual(t, "POST, OPTIONS", resp.Header.Get(HeaderAllow))
    83  
    84  	resp, err = app.Test(httptest.NewRequest(MethodPut, "/", nil))
    85  	utils.AssertEqual(t, nil, err)
    86  	utils.AssertEqual(t, 405, resp.StatusCode)
    87  	utils.AssertEqual(t, "POST, OPTIONS", resp.Header.Get(HeaderAllow))
    88  
    89  	app.Get("/", testEmptyHandler)
    90  
    91  	resp, err = app.Test(httptest.NewRequest(MethodTrace, "/", nil))
    92  	utils.AssertEqual(t, nil, err)
    93  	utils.AssertEqual(t, 405, resp.StatusCode)
    94  	utils.AssertEqual(t, "GET, HEAD, POST, OPTIONS", resp.Header.Get(HeaderAllow))
    95  
    96  	resp, err = app.Test(httptest.NewRequest(MethodPatch, "/", nil))
    97  	utils.AssertEqual(t, nil, err)
    98  	utils.AssertEqual(t, 405, resp.StatusCode)
    99  	utils.AssertEqual(t, "GET, HEAD, POST, OPTIONS", resp.Header.Get(HeaderAllow))
   100  
   101  	resp, err = app.Test(httptest.NewRequest(MethodPut, "/", nil))
   102  	utils.AssertEqual(t, nil, err)
   103  	utils.AssertEqual(t, 405, resp.StatusCode)
   104  	utils.AssertEqual(t, "GET, HEAD, POST, OPTIONS", resp.Header.Get(HeaderAllow))
   105  }
   106  
   107  func Test_App_Custom_Middleware_404_Should_Not_SetMethodNotAllowed(t *testing.T) {
   108  	t.Parallel()
   109  	app := New()
   110  
   111  	app.Use(func(c *Ctx) error {
   112  		return c.SendStatus(404)
   113  	})
   114  
   115  	app.Post("/", testEmptyHandler)
   116  
   117  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
   118  	utils.AssertEqual(t, nil, err)
   119  	utils.AssertEqual(t, 404, resp.StatusCode)
   120  
   121  	g := app.Group("/with-next", func(c *Ctx) error {
   122  		return c.Status(404).Next()
   123  	})
   124  
   125  	g.Post("/", testEmptyHandler)
   126  
   127  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/with-next", nil))
   128  	utils.AssertEqual(t, nil, err)
   129  	utils.AssertEqual(t, 404, resp.StatusCode)
   130  }
   131  
   132  func Test_App_ServerErrorHandler_SmallReadBuffer(t *testing.T) {
   133  	t.Parallel()
   134  	expectedError := regexp.MustCompile(
   135  		`error when reading request headers: small read buffer\. Increase ReadBufferSize\. Buffer size=4096, contents: "GET / HTTP/1.1\\r\\nHost: example\.com\\r\\nVery-Long-Header: -+`,
   136  	)
   137  	app := New()
   138  
   139  	app.Get("/", func(c *Ctx) error {
   140  		panic(errors.New("should never called"))
   141  	})
   142  
   143  	request := httptest.NewRequest(MethodGet, "/", nil)
   144  	logHeaderSlice := make([]string, 5000)
   145  	request.Header.Set("Very-Long-Header", strings.Join(logHeaderSlice, "-"))
   146  	_, err := app.Test(request)
   147  	if err == nil {
   148  		t.Error("Expect an error at app.Test(request)")
   149  	}
   150  
   151  	utils.AssertEqual(
   152  		t,
   153  		true,
   154  		expectedError.MatchString(err.Error()),
   155  		fmt.Sprintf("Has: %s, expected pattern: %s", err.Error(), expectedError.String()),
   156  	)
   157  }
   158  
   159  func Test_App_Errors(t *testing.T) {
   160  	t.Parallel()
   161  	app := New(Config{
   162  		BodyLimit: 4,
   163  	})
   164  
   165  	app.Get("/", func(c *Ctx) error {
   166  		return errors.New("hi, i'm an error")
   167  	})
   168  
   169  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
   170  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   171  	utils.AssertEqual(t, 500, resp.StatusCode, "Status code")
   172  
   173  	body, err := io.ReadAll(resp.Body)
   174  	utils.AssertEqual(t, nil, err)
   175  	utils.AssertEqual(t, "hi, i'm an error", string(body))
   176  
   177  	_, err = app.Test(httptest.NewRequest(MethodGet, "/", strings.NewReader("big body")))
   178  	if err != nil {
   179  		utils.AssertEqual(t, "body size exceeds the given limit", err.Error(), "app.Test(req)")
   180  	}
   181  }
   182  
   183  func Test_App_ErrorHandler_Custom(t *testing.T) {
   184  	t.Parallel()
   185  	app := New(Config{
   186  		ErrorHandler: func(c *Ctx, err error) error {
   187  			return c.Status(200).SendString("hi, i'm an custom error")
   188  		},
   189  	})
   190  
   191  	app.Get("/", func(c *Ctx) error {
   192  		return errors.New("hi, i'm an error")
   193  	})
   194  
   195  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
   196  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   197  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   198  
   199  	body, err := io.ReadAll(resp.Body)
   200  	utils.AssertEqual(t, nil, err)
   201  	utils.AssertEqual(t, "hi, i'm an custom error", string(body))
   202  }
   203  
   204  func Test_App_ErrorHandler_HandlerStack(t *testing.T) {
   205  	t.Parallel()
   206  	app := New(Config{
   207  		ErrorHandler: func(c *Ctx, err error) error {
   208  			utils.AssertEqual(t, "1: USE error", err.Error())
   209  			return DefaultErrorHandler(c, err)
   210  		},
   211  	})
   212  	app.Use("/", func(c *Ctx) error {
   213  		err := c.Next() // call next USE
   214  		utils.AssertEqual(t, "2: USE error", err.Error())
   215  		return errors.New("1: USE error")
   216  	}, func(c *Ctx) error {
   217  		err := c.Next() // call [0] GET
   218  		utils.AssertEqual(t, "0: GET error", err.Error())
   219  		return errors.New("2: USE error")
   220  	})
   221  	app.Get("/", func(c *Ctx) error {
   222  		return errors.New("0: GET error")
   223  	})
   224  
   225  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
   226  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   227  	utils.AssertEqual(t, 500, resp.StatusCode, "Status code")
   228  
   229  	body, err := io.ReadAll(resp.Body)
   230  	utils.AssertEqual(t, nil, err)
   231  	utils.AssertEqual(t, "1: USE error", string(body))
   232  }
   233  
   234  func Test_App_ErrorHandler_RouteStack(t *testing.T) {
   235  	t.Parallel()
   236  	app := New(Config{
   237  		ErrorHandler: func(c *Ctx, err error) error {
   238  			utils.AssertEqual(t, "1: USE error", err.Error())
   239  			return DefaultErrorHandler(c, err)
   240  		},
   241  	})
   242  	app.Use("/", func(c *Ctx) error {
   243  		err := c.Next()
   244  		utils.AssertEqual(t, "0: GET error", err.Error())
   245  		return errors.New("1: USE error") // [2] call ErrorHandler
   246  	})
   247  	app.Get("/test", func(c *Ctx) error {
   248  		return errors.New("0: GET error") // [1] return to USE
   249  	})
   250  
   251  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/test", nil))
   252  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   253  	utils.AssertEqual(t, 500, resp.StatusCode, "Status code")
   254  
   255  	body, err := io.ReadAll(resp.Body)
   256  	utils.AssertEqual(t, nil, err)
   257  	utils.AssertEqual(t, "1: USE error", string(body))
   258  }
   259  
   260  func Test_App_serverErrorHandler_Internal_Error(t *testing.T) {
   261  	t.Parallel()
   262  	app := New()
   263  	msg := "test err"
   264  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   265  	defer app.ReleaseCtx(c)
   266  	app.serverErrorHandler(c.fasthttp, errors.New(msg))
   267  	utils.AssertEqual(t, string(c.fasthttp.Response.Body()), msg)
   268  	utils.AssertEqual(t, c.fasthttp.Response.StatusCode(), StatusBadRequest)
   269  }
   270  
   271  func Test_App_serverErrorHandler_Network_Error(t *testing.T) {
   272  	t.Parallel()
   273  	app := New()
   274  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   275  	defer app.ReleaseCtx(c)
   276  	app.serverErrorHandler(c.fasthttp, &net.DNSError{
   277  		Err:       "test error",
   278  		Name:      "test host",
   279  		IsTimeout: false,
   280  	})
   281  	utils.AssertEqual(t, string(c.fasthttp.Response.Body()), utils.StatusMessage(StatusBadGateway))
   282  	utils.AssertEqual(t, c.fasthttp.Response.StatusCode(), StatusBadGateway)
   283  }
   284  
   285  func Test_App_Nested_Params(t *testing.T) {
   286  	t.Parallel()
   287  	app := New()
   288  
   289  	app.Get("/test", func(c *Ctx) error {
   290  		return c.Status(400).Send([]byte("Should move on"))
   291  	})
   292  	app.Get("/test/:param", func(c *Ctx) error {
   293  		return c.Status(400).Send([]byte("Should move on"))
   294  	})
   295  	app.Get("/test/:param/test", func(c *Ctx) error {
   296  		return c.Status(400).Send([]byte("Should move on"))
   297  	})
   298  	app.Get("/test/:param/test/:param2", func(c *Ctx) error {
   299  		return c.Status(200).Send([]byte("Good job"))
   300  	})
   301  
   302  	req := httptest.NewRequest(MethodGet, "/test/john/test/doe", nil)
   303  	resp, err := app.Test(req)
   304  
   305  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   306  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   307  }
   308  
   309  func Test_App_Use_Params(t *testing.T) {
   310  	t.Parallel()
   311  	app := New()
   312  
   313  	app.Use("/prefix/:param", func(c *Ctx) error {
   314  		utils.AssertEqual(t, "john", c.Params("param"))
   315  		return nil
   316  	})
   317  
   318  	app.Use("/foo/:bar?", func(c *Ctx) error {
   319  		utils.AssertEqual(t, "foobar", c.Params("bar", "foobar"))
   320  		return nil
   321  	})
   322  
   323  	app.Use("/:param/*", func(c *Ctx) error {
   324  		utils.AssertEqual(t, "john", c.Params("param"))
   325  		utils.AssertEqual(t, "doe", c.Params("*"))
   326  		return nil
   327  	})
   328  
   329  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/prefix/john", nil))
   330  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   331  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   332  
   333  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/john/doe", nil))
   334  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   335  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   336  
   337  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/foo", nil))
   338  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   339  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   340  
   341  	defer func() {
   342  		if err := recover(); err != nil {
   343  			utils.AssertEqual(t, "use: invalid handler func()\n", fmt.Sprintf("%v", err))
   344  		}
   345  	}()
   346  
   347  	app.Use("/:param/*", func() {
   348  		// this should panic
   349  	})
   350  }
   351  
   352  func Test_App_Use_UnescapedPath(t *testing.T) {
   353  	t.Parallel()
   354  	app := New(Config{UnescapePath: true, CaseSensitive: true})
   355  
   356  	app.Use("/cRéeR/:param", func(c *Ctx) error {
   357  		utils.AssertEqual(t, "/cRéeR/اختبار", c.Path())
   358  		return c.SendString(c.Params("param"))
   359  	})
   360  
   361  	app.Use("/abc", func(c *Ctx) error {
   362  		utils.AssertEqual(t, "/AbC", c.Path())
   363  		return nil
   364  	})
   365  
   366  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/cR%C3%A9eR/%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1", nil))
   367  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   368  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   369  
   370  	body, err := io.ReadAll(resp.Body)
   371  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   372  	// check the param result
   373  	utils.AssertEqual(t, "اختبار", app.getString(body))
   374  
   375  	// with lowercase letters
   376  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/cr%C3%A9er/%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1", nil))
   377  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   378  	utils.AssertEqual(t, StatusNotFound, resp.StatusCode, "Status code")
   379  }
   380  
   381  func Test_App_Use_CaseSensitive(t *testing.T) {
   382  	t.Parallel()
   383  	app := New(Config{CaseSensitive: true})
   384  
   385  	app.Use("/abc", func(c *Ctx) error {
   386  		return c.SendString(c.Path())
   387  	})
   388  
   389  	// wrong letters in the requested route -> 404
   390  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/AbC", nil))
   391  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   392  	utils.AssertEqual(t, StatusNotFound, resp.StatusCode, "Status code")
   393  
   394  	// right letters in the requrested route -> 200
   395  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/abc", nil))
   396  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   397  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   398  
   399  	// check the detected path when the case insensitive recognition is activated
   400  	app.config.CaseSensitive = false
   401  	// check the case sensitive feature
   402  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/AbC", nil))
   403  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   404  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   405  
   406  	body, err := io.ReadAll(resp.Body)
   407  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   408  	// check the detected path result
   409  	utils.AssertEqual(t, "/AbC", app.getString(body))
   410  }
   411  
   412  func Test_App_Not_Use_StrictRouting(t *testing.T) {
   413  	t.Parallel()
   414  	app := New()
   415  
   416  	app.Use("/abc", func(c *Ctx) error {
   417  		return c.SendString(c.Path())
   418  	})
   419  
   420  	g := app.Group("/foo")
   421  	g.Use("/", func(c *Ctx) error {
   422  		return c.SendString(c.Path())
   423  	})
   424  
   425  	// wrong path in the requested route -> 404
   426  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/abc/", nil))
   427  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   428  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   429  
   430  	// right path in the requrested route -> 200
   431  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/abc", nil))
   432  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   433  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   434  
   435  	// wrong path with group in the requested route -> 404
   436  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/foo", nil))
   437  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   438  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   439  
   440  	// right path with group in the requrested route -> 200
   441  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/foo/", nil))
   442  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   443  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   444  }
   445  
   446  func Test_App_Use_MultiplePrefix(t *testing.T) {
   447  	t.Parallel()
   448  	app := New()
   449  
   450  	app.Use([]string{"/john", "/doe"}, func(c *Ctx) error {
   451  		return c.SendString(c.Path())
   452  	})
   453  
   454  	g := app.Group("/test")
   455  	g.Use([]string{"/john", "/doe"}, func(c *Ctx) error {
   456  		return c.SendString(c.Path())
   457  	})
   458  
   459  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/john", nil))
   460  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   461  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   462  
   463  	body, err := io.ReadAll(resp.Body)
   464  	utils.AssertEqual(t, nil, err)
   465  	utils.AssertEqual(t, "/john", string(body))
   466  
   467  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/doe", nil))
   468  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   469  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   470  
   471  	body, err = io.ReadAll(resp.Body)
   472  	utils.AssertEqual(t, nil, err)
   473  	utils.AssertEqual(t, "/doe", string(body))
   474  
   475  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test/john", nil))
   476  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   477  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   478  
   479  	body, err = io.ReadAll(resp.Body)
   480  	utils.AssertEqual(t, nil, err)
   481  	utils.AssertEqual(t, "/test/john", string(body))
   482  
   483  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test/doe", nil))
   484  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   485  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   486  
   487  	body, err = io.ReadAll(resp.Body)
   488  	utils.AssertEqual(t, nil, err)
   489  	utils.AssertEqual(t, "/test/doe", string(body))
   490  }
   491  
   492  func Test_App_Use_StrictRouting(t *testing.T) {
   493  	t.Parallel()
   494  	app := New(Config{StrictRouting: true})
   495  
   496  	app.Get("/abc", func(c *Ctx) error {
   497  		return c.SendString(c.Path())
   498  	})
   499  
   500  	g := app.Group("/foo")
   501  	g.Get("/", func(c *Ctx) error {
   502  		return c.SendString(c.Path())
   503  	})
   504  
   505  	// wrong path in the requested route -> 404
   506  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/abc/", nil))
   507  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   508  	utils.AssertEqual(t, StatusNotFound, resp.StatusCode, "Status code")
   509  
   510  	// right path in the requrested route -> 200
   511  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/abc", nil))
   512  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   513  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   514  
   515  	// wrong path with group in the requested route -> 404
   516  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/foo", nil))
   517  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   518  	utils.AssertEqual(t, StatusNotFound, resp.StatusCode, "Status code")
   519  
   520  	// right path with group in the requrested route -> 200
   521  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/foo/", nil))
   522  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   523  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   524  }
   525  
   526  func Test_App_Add_Method_Test(t *testing.T) {
   527  	t.Parallel()
   528  	defer func() {
   529  		if err := recover(); err != nil {
   530  			utils.AssertEqual(t, "add: invalid http method JANE\n", fmt.Sprintf("%v", err))
   531  		}
   532  	}()
   533  
   534  	methods := append(DefaultMethods, "JOHN") //nolint:gocritic // We want a new slice here
   535  	app := New(Config{
   536  		RequestMethods: methods,
   537  	})
   538  
   539  	app.Add("JOHN", "/doe", testEmptyHandler)
   540  
   541  	resp, err := app.Test(httptest.NewRequest("JOHN", "/doe", nil))
   542  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   543  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   544  
   545  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/doe", nil))
   546  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   547  	utils.AssertEqual(t, StatusMethodNotAllowed, resp.StatusCode, "Status code")
   548  
   549  	resp, err = app.Test(httptest.NewRequest("UNKNOWN", "/doe", nil))
   550  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   551  	utils.AssertEqual(t, StatusBadRequest, resp.StatusCode, "Status code")
   552  
   553  	app.Add("JANE", "/doe", testEmptyHandler)
   554  }
   555  
   556  // go test -run Test_App_GETOnly
   557  func Test_App_GETOnly(t *testing.T) {
   558  	t.Parallel()
   559  	app := New(Config{
   560  		GETOnly: true,
   561  	})
   562  
   563  	app.Post("/", func(c *Ctx) error {
   564  		return c.SendString("Hello 👋!")
   565  	})
   566  
   567  	req := httptest.NewRequest(MethodPost, "/", nil)
   568  	resp, err := app.Test(req)
   569  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   570  	utils.AssertEqual(t, StatusMethodNotAllowed, resp.StatusCode, "Status code")
   571  }
   572  
   573  func Test_App_Use_Params_Group(t *testing.T) {
   574  	t.Parallel()
   575  	app := New()
   576  
   577  	group := app.Group("/prefix/:param/*")
   578  	group.Use("/", func(c *Ctx) error {
   579  		return c.Next()
   580  	})
   581  	group.Get("/test", func(c *Ctx) error {
   582  		utils.AssertEqual(t, "john", c.Params("param"))
   583  		utils.AssertEqual(t, "doe", c.Params("*"))
   584  		return nil
   585  	})
   586  
   587  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/prefix/john/doe/test", nil))
   588  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   589  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   590  }
   591  
   592  func Test_App_Chaining(t *testing.T) {
   593  	t.Parallel()
   594  	n := func(c *Ctx) error {
   595  		return c.Next()
   596  	}
   597  	app := New()
   598  	app.Use("/john", n, n, n, n, func(c *Ctx) error {
   599  		return c.SendStatus(202)
   600  	})
   601  	// check handler count for registered HEAD route
   602  	utils.AssertEqual(t, 5, len(app.stack[app.methodInt(MethodHead)][0].Handlers), "app.Test(req)")
   603  
   604  	req := httptest.NewRequest(MethodPost, "/john", nil)
   605  
   606  	resp, err := app.Test(req)
   607  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   608  	utils.AssertEqual(t, 202, resp.StatusCode, "Status code")
   609  
   610  	app.Get("/test", n, n, n, n, func(c *Ctx) error {
   611  		return c.SendStatus(203)
   612  	})
   613  
   614  	req = httptest.NewRequest(MethodGet, "/test", nil)
   615  
   616  	resp, err = app.Test(req)
   617  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   618  	utils.AssertEqual(t, 203, resp.StatusCode, "Status code")
   619  }
   620  
   621  func Test_App_Order(t *testing.T) {
   622  	t.Parallel()
   623  	app := New()
   624  
   625  	app.Get("/test", func(c *Ctx) error {
   626  		_, err := c.Write([]byte("1"))
   627  		utils.AssertEqual(t, nil, err)
   628  		return c.Next()
   629  	})
   630  
   631  	app.All("/test", func(c *Ctx) error {
   632  		_, err := c.Write([]byte("2"))
   633  		utils.AssertEqual(t, nil, err)
   634  		return c.Next()
   635  	})
   636  
   637  	app.Use(func(c *Ctx) error {
   638  		_, err := c.Write([]byte("3"))
   639  		utils.AssertEqual(t, nil, err)
   640  		return nil
   641  	})
   642  
   643  	req := httptest.NewRequest(MethodGet, "/test", nil)
   644  
   645  	resp, err := app.Test(req)
   646  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   647  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   648  
   649  	body, err := io.ReadAll(resp.Body)
   650  	utils.AssertEqual(t, nil, err)
   651  	utils.AssertEqual(t, "123", string(body))
   652  }
   653  
   654  func Test_App_Methods(t *testing.T) {
   655  	t.Parallel()
   656  	dummyHandler := testEmptyHandler
   657  
   658  	app := New()
   659  
   660  	app.Connect("/:john?/:doe?", dummyHandler)
   661  	testStatus200(t, app, "/john/doe", "CONNECT")
   662  
   663  	app.Put("/:john?/:doe?", dummyHandler)
   664  	testStatus200(t, app, "/john/doe", MethodPut)
   665  
   666  	app.Post("/:john?/:doe?", dummyHandler)
   667  	testStatus200(t, app, "/john/doe", MethodPost)
   668  
   669  	app.Delete("/:john?/:doe?", dummyHandler)
   670  	testStatus200(t, app, "/john/doe", MethodDelete)
   671  
   672  	app.Head("/:john?/:doe?", dummyHandler)
   673  	testStatus200(t, app, "/john/doe", MethodHead)
   674  
   675  	app.Patch("/:john?/:doe?", dummyHandler)
   676  	testStatus200(t, app, "/john/doe", MethodPatch)
   677  
   678  	app.Options("/:john?/:doe?", dummyHandler)
   679  	testStatus200(t, app, "/john/doe", MethodOptions)
   680  
   681  	app.Trace("/:john?/:doe?", dummyHandler)
   682  	testStatus200(t, app, "/john/doe", MethodTrace)
   683  
   684  	app.Get("/:john?/:doe?", dummyHandler)
   685  	testStatus200(t, app, "/john/doe", MethodGet)
   686  
   687  	app.All("/:john?/:doe?", dummyHandler)
   688  	testStatus200(t, app, "/john/doe", MethodPost)
   689  
   690  	app.Use("/:john?/:doe?", dummyHandler)
   691  	testStatus200(t, app, "/john/doe", MethodGet)
   692  }
   693  
   694  func Test_App_Route_Naming(t *testing.T) {
   695  	t.Parallel()
   696  	app := New()
   697  	handler := func(c *Ctx) error {
   698  		return c.SendStatus(StatusOK)
   699  	}
   700  	app.Get("/john", handler).Name("john")
   701  	app.Delete("/doe", handler)
   702  	app.Name("doe")
   703  
   704  	jane := app.Group("/jane").Name("jane.")
   705  	group := app.Group("/group")
   706  	subGroup := jane.Group("/sub-group").Name("sub.")
   707  
   708  	jane.Get("/test", handler).Name("test")
   709  	jane.Trace("/trace", handler).Name("trace")
   710  
   711  	group.Get("/test", handler).Name("test")
   712  
   713  	app.Post("/post", handler).Name("post")
   714  
   715  	subGroup.Get("/done", handler).Name("done")
   716  
   717  	utils.AssertEqual(t, "post", app.GetRoute("post").Name)
   718  	utils.AssertEqual(t, "john", app.GetRoute("john").Name)
   719  	utils.AssertEqual(t, "jane.test", app.GetRoute("jane.test").Name)
   720  	utils.AssertEqual(t, "jane.trace", app.GetRoute("jane.trace").Name)
   721  	utils.AssertEqual(t, "jane.sub.done", app.GetRoute("jane.sub.done").Name)
   722  	utils.AssertEqual(t, "test", app.GetRoute("test").Name)
   723  }
   724  
   725  func Test_App_New(t *testing.T) {
   726  	t.Parallel()
   727  	app := New()
   728  	app.Get("/", testEmptyHandler)
   729  
   730  	appConfig := New(Config{
   731  		Immutable: true,
   732  	})
   733  	appConfig.Get("/", testEmptyHandler)
   734  }
   735  
   736  func Test_App_Config(t *testing.T) {
   737  	t.Parallel()
   738  	app := New(Config{
   739  		DisableStartupMessage: true,
   740  	})
   741  	utils.AssertEqual(t, true, app.Config().DisableStartupMessage)
   742  }
   743  
   744  func Test_App_Shutdown(t *testing.T) {
   745  	t.Parallel()
   746  	t.Run("success", func(t *testing.T) {
   747  		t.Parallel()
   748  		app := New(Config{
   749  			DisableStartupMessage: true,
   750  		})
   751  		utils.AssertEqual(t, true, app.Shutdown() == nil)
   752  	})
   753  
   754  	t.Run("no server", func(t *testing.T) {
   755  		t.Parallel()
   756  		app := &App{}
   757  		if err := app.Shutdown(); err != nil {
   758  			if err.Error() != "shutdown: server is not running" {
   759  				t.Fatal()
   760  			}
   761  		}
   762  	})
   763  }
   764  
   765  func Test_App_ShutdownWithTimeout(t *testing.T) {
   766  	t.Parallel()
   767  	app := New()
   768  	app.Get("/", func(ctx *Ctx) error {
   769  		time.Sleep(5 * time.Second)
   770  		return ctx.SendString("body")
   771  	})
   772  	ln := fasthttputil.NewInmemoryListener()
   773  	go func() {
   774  		utils.AssertEqual(t, nil, app.Listener(ln))
   775  	}()
   776  	time.Sleep(1 * time.Second)
   777  	go func() {
   778  		conn, err := ln.Dial()
   779  		if err != nil {
   780  			t.Errorf("unexepcted error: %v", err)
   781  		}
   782  
   783  		if _, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")); err != nil {
   784  			t.Errorf("unexpected error: %v", err)
   785  		}
   786  	}()
   787  	time.Sleep(1 * time.Second)
   788  
   789  	shutdownErr := make(chan error)
   790  	go func() {
   791  		shutdownErr <- app.ShutdownWithTimeout(1 * time.Second)
   792  	}()
   793  
   794  	timer := time.NewTimer(time.Second * 5)
   795  	select {
   796  	case <-timer.C:
   797  		t.Fatal("idle connections not closed on shutdown")
   798  	case err := <-shutdownErr:
   799  		if err == nil || !errors.Is(err, context.DeadlineExceeded) {
   800  			t.Fatalf("unexpected err %v. Expecting %v", err, context.DeadlineExceeded)
   801  		}
   802  	}
   803  }
   804  
   805  func Test_App_ShutdownWithContext(t *testing.T) {
   806  	t.Parallel()
   807  
   808  	app := New()
   809  	app.Get("/", func(ctx *Ctx) error {
   810  		time.Sleep(5 * time.Second)
   811  		return ctx.SendString("body")
   812  	})
   813  
   814  	ln := fasthttputil.NewInmemoryListener()
   815  
   816  	go func() {
   817  		utils.AssertEqual(t, nil, app.Listener(ln))
   818  	}()
   819  
   820  	time.Sleep(1 * time.Second)
   821  
   822  	go func() {
   823  		conn, err := ln.Dial()
   824  		if err != nil {
   825  			t.Errorf("unexepcted error: %v", err)
   826  		}
   827  
   828  		if _, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")); err != nil {
   829  			t.Errorf("unexpected error: %v", err)
   830  		}
   831  	}()
   832  
   833  	time.Sleep(1 * time.Second)
   834  
   835  	shutdownErr := make(chan error)
   836  	go func() {
   837  		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
   838  		defer cancel()
   839  		shutdownErr <- app.ShutdownWithContext(ctx)
   840  	}()
   841  
   842  	select {
   843  	case <-time.After(5 * time.Second):
   844  		t.Fatal("idle connections not closed on shutdown")
   845  	case err := <-shutdownErr:
   846  		if err == nil || !errors.Is(err, context.DeadlineExceeded) {
   847  			t.Fatalf("unexpected err %v. Expecting %v", err, context.DeadlineExceeded)
   848  		}
   849  	}
   850  }
   851  
   852  // go test -run Test_App_Static_Index_Default
   853  func Test_App_Static_Index_Default(t *testing.T) {
   854  	t.Parallel()
   855  	app := New()
   856  
   857  	app.Static("/prefix", "./.github/workflows")
   858  	app.Static("", "./.github/")
   859  	app.Static("test", "", Static{Index: "index.html"})
   860  
   861  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
   862  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   863  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   864  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
   865  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
   866  
   867  	body, err := io.ReadAll(resp.Body)
   868  	utils.AssertEqual(t, nil, err)
   869  	utils.AssertEqual(t, true, strings.Contains(string(body), "Hello, World!"))
   870  
   871  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/not-found", nil))
   872  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   873  	utils.AssertEqual(t, 404, resp.StatusCode, "Status code")
   874  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
   875  	utils.AssertEqual(t, MIMETextPlainCharsetUTF8, resp.Header.Get(HeaderContentType))
   876  
   877  	body, err = io.ReadAll(resp.Body)
   878  	utils.AssertEqual(t, nil, err)
   879  	utils.AssertEqual(t, "Cannot GET /not-found", string(body))
   880  }
   881  
   882  // go test -run Test_App_Static_Index
   883  func Test_App_Static_Direct(t *testing.T) {
   884  	t.Parallel()
   885  	app := New()
   886  
   887  	app.Static("/", "./.github")
   888  
   889  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/index.html", nil))
   890  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   891  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   892  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
   893  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
   894  
   895  	body, err := io.ReadAll(resp.Body)
   896  	utils.AssertEqual(t, nil, err)
   897  	utils.AssertEqual(t, true, strings.Contains(string(body), "Hello, World!"))
   898  
   899  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/testdata/testRoutes.json", nil))
   900  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   901  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   902  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
   903  	utils.AssertEqual(t, MIMEApplicationJSON, resp.Header.Get("Content-Type"))
   904  	utils.AssertEqual(t, "", resp.Header.Get(HeaderCacheControl), "CacheControl Control")
   905  
   906  	body, err = io.ReadAll(resp.Body)
   907  	utils.AssertEqual(t, nil, err)
   908  	utils.AssertEqual(t, true, strings.Contains(string(body), "test_routes"))
   909  }
   910  
   911  // go test -run Test_App_Static_MaxAge
   912  func Test_App_Static_MaxAge(t *testing.T) {
   913  	t.Parallel()
   914  	app := New()
   915  
   916  	app.Static("/", "./.github", Static{MaxAge: 100})
   917  
   918  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/index.html", nil))
   919  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   920  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   921  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
   922  	utils.AssertEqual(t, "text/html; charset=utf-8", resp.Header.Get(HeaderContentType))
   923  	utils.AssertEqual(t, "public, max-age=100", resp.Header.Get(HeaderCacheControl), "CacheControl Control")
   924  }
   925  
   926  // go test -run Test_App_Static_Custom_CacheControl
   927  func Test_App_Static_Custom_CacheControl(t *testing.T) {
   928  	t.Parallel()
   929  	app := New()
   930  
   931  	app.Static("/", "./.github", Static{ModifyResponse: func(c *Ctx) error {
   932  		if strings.Contains(c.GetRespHeader("Content-Type"), "text/html") {
   933  			c.Response().Header.Set("Cache-Control", "no-cache, no-store, must-revalidate")
   934  		}
   935  		return nil
   936  	}})
   937  
   938  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/index.html", nil))
   939  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   940  	utils.AssertEqual(t, "no-cache, no-store, must-revalidate", resp.Header.Get(HeaderCacheControl), "CacheControl Control")
   941  
   942  	respNormal, errNormal := app.Test(httptest.NewRequest(MethodGet, "/config.yml", nil))
   943  	utils.AssertEqual(t, nil, errNormal, "app.Test(req)")
   944  	utils.AssertEqual(t, "", respNormal.Header.Get(HeaderCacheControl), "CacheControl Control")
   945  }
   946  
   947  // go test -run Test_App_Static_Download
   948  func Test_App_Static_Download(t *testing.T) {
   949  	t.Parallel()
   950  	app := New()
   951  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   952  	defer app.ReleaseCtx(c)
   953  
   954  	app.Static("/fiber.png", "./.github/testdata/fs/img/fiber.png", Static{Download: true})
   955  
   956  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/fiber.png", nil))
   957  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   958  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   959  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
   960  	utils.AssertEqual(t, "image/png", resp.Header.Get(HeaderContentType))
   961  	utils.AssertEqual(t, `attachment`, resp.Header.Get(HeaderContentDisposition))
   962  }
   963  
   964  // go test -run Test_App_Static_Group
   965  func Test_App_Static_Group(t *testing.T) {
   966  	t.Parallel()
   967  	app := New()
   968  
   969  	grp := app.Group("/v1", func(c *Ctx) error {
   970  		c.Set("Test-Header", "123")
   971  		return c.Next()
   972  	})
   973  
   974  	grp.Static("/v2", "./.github/index.html")
   975  
   976  	req := httptest.NewRequest(MethodGet, "/v1/v2", nil)
   977  	resp, err := app.Test(req)
   978  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   979  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   980  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
   981  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
   982  	utils.AssertEqual(t, "123", resp.Header.Get("Test-Header"))
   983  
   984  	grp = app.Group("/v2")
   985  	grp.Static("/v3*", "./.github/index.html")
   986  
   987  	req = httptest.NewRequest(MethodGet, "/v2/v3/john/doe", nil)
   988  	resp, err = app.Test(req)
   989  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   990  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   991  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
   992  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
   993  }
   994  
   995  func Test_App_Static_Wildcard(t *testing.T) {
   996  	t.Parallel()
   997  	app := New()
   998  
   999  	app.Static("*", "./.github/index.html")
  1000  
  1001  	req := httptest.NewRequest(MethodGet, "/yesyes/john/doe", nil)
  1002  	resp, err := app.Test(req)
  1003  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1004  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1005  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1006  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
  1007  
  1008  	body, err := io.ReadAll(resp.Body)
  1009  	utils.AssertEqual(t, nil, err)
  1010  	utils.AssertEqual(t, true, strings.Contains(string(body), "Test file"))
  1011  }
  1012  
  1013  func Test_App_Static_Prefix_Wildcard(t *testing.T) {
  1014  	t.Parallel()
  1015  	app := New()
  1016  
  1017  	app.Static("/test/*", "./.github/index.html")
  1018  
  1019  	req := httptest.NewRequest(MethodGet, "/test/john/doe", nil)
  1020  	resp, err := app.Test(req)
  1021  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1022  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1023  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1024  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
  1025  
  1026  	app.Static("/my/nameisjohn*", "./.github/index.html")
  1027  
  1028  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/my/nameisjohn/no/its/not", nil))
  1029  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1030  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1031  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1032  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
  1033  
  1034  	body, err := io.ReadAll(resp.Body)
  1035  	utils.AssertEqual(t, nil, err)
  1036  	utils.AssertEqual(t, true, strings.Contains(string(body), "Test file"))
  1037  }
  1038  
  1039  func Test_App_Static_Prefix(t *testing.T) {
  1040  	t.Parallel()
  1041  	app := New()
  1042  	app.Static("/john", "./.github")
  1043  
  1044  	req := httptest.NewRequest(MethodGet, "/john/index.html", nil)
  1045  	resp, err := app.Test(req)
  1046  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1047  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1048  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1049  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
  1050  
  1051  	app.Static("/prefix", "./.github/testdata")
  1052  
  1053  	req = httptest.NewRequest(MethodGet, "/prefix/index.html", nil)
  1054  	resp, err = app.Test(req)
  1055  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1056  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1057  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1058  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
  1059  
  1060  	app.Static("/single", "./.github/testdata/testRoutes.json")
  1061  
  1062  	req = httptest.NewRequest(MethodGet, "/single", nil)
  1063  	resp, err = app.Test(req)
  1064  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1065  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1066  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1067  	utils.AssertEqual(t, MIMEApplicationJSON, resp.Header.Get(HeaderContentType))
  1068  }
  1069  
  1070  func Test_App_Static_Trailing_Slash(t *testing.T) {
  1071  	t.Parallel()
  1072  	app := New()
  1073  	app.Static("/john", "./.github")
  1074  
  1075  	req := httptest.NewRequest(MethodGet, "/john/", nil)
  1076  	resp, err := app.Test(req)
  1077  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1078  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1079  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1080  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
  1081  
  1082  	app.Static("/john_without_index", "./.github/testdata/fs/css")
  1083  
  1084  	req = httptest.NewRequest(MethodGet, "/john_without_index/", nil)
  1085  	resp, err = app.Test(req)
  1086  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1087  	utils.AssertEqual(t, 404, resp.StatusCode, "Status code")
  1088  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1089  	utils.AssertEqual(t, MIMETextPlainCharsetUTF8, resp.Header.Get(HeaderContentType))
  1090  
  1091  	app.Static("/john/", "./.github")
  1092  
  1093  	req = httptest.NewRequest(MethodGet, "/john/", nil)
  1094  	resp, err = app.Test(req)
  1095  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1096  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1097  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1098  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
  1099  
  1100  	req = httptest.NewRequest(MethodGet, "/john", nil)
  1101  	resp, err = app.Test(req)
  1102  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1103  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1104  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1105  	utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
  1106  
  1107  	app.Static("/john_without_index/", "./.github/testdata/fs/css")
  1108  
  1109  	req = httptest.NewRequest(MethodGet, "/john_without_index/", nil)
  1110  	resp, err = app.Test(req)
  1111  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1112  	utils.AssertEqual(t, 404, resp.StatusCode, "Status code")
  1113  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1114  	utils.AssertEqual(t, MIMETextPlainCharsetUTF8, resp.Header.Get(HeaderContentType))
  1115  }
  1116  
  1117  func Test_App_Static_Next(t *testing.T) {
  1118  	t.Parallel()
  1119  	app := New()
  1120  	app.Static("/", ".github", Static{
  1121  		Next: func(c *Ctx) bool {
  1122  			// If value of the header is any other from "skip"
  1123  			// c.Next() will be invoked
  1124  			return c.Get("X-Custom-Header") == "skip"
  1125  		},
  1126  	})
  1127  	app.Get("/", func(c *Ctx) error {
  1128  		return c.SendString("You've skipped app.Static")
  1129  	})
  1130  
  1131  	t.Run("app.Static is skipped: invoking Get handler", func(t *testing.T) {
  1132  		t.Parallel()
  1133  		req := httptest.NewRequest(MethodGet, "/", nil)
  1134  		req.Header.Set("X-Custom-Header", "skip")
  1135  		resp, err := app.Test(req)
  1136  		utils.AssertEqual(t, nil, err)
  1137  		utils.AssertEqual(t, 200, resp.StatusCode)
  1138  		utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1139  		utils.AssertEqual(t, MIMETextPlainCharsetUTF8, resp.Header.Get(HeaderContentType))
  1140  
  1141  		body, err := io.ReadAll(resp.Body)
  1142  		utils.AssertEqual(t, nil, err)
  1143  		utils.AssertEqual(t, true, strings.Contains(string(body), "You've skipped app.Static"))
  1144  	})
  1145  
  1146  	t.Run("app.Static is not skipped: serving index.html", func(t *testing.T) {
  1147  		t.Parallel()
  1148  		req := httptest.NewRequest(MethodGet, "/", nil)
  1149  		req.Header.Set("X-Custom-Header", "don't skip")
  1150  		resp, err := app.Test(req)
  1151  		utils.AssertEqual(t, nil, err)
  1152  		utils.AssertEqual(t, 200, resp.StatusCode)
  1153  		utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1154  		utils.AssertEqual(t, MIMETextHTMLCharsetUTF8, resp.Header.Get(HeaderContentType))
  1155  
  1156  		body, err := io.ReadAll(resp.Body)
  1157  		utils.AssertEqual(t, nil, err)
  1158  		utils.AssertEqual(t, true, strings.Contains(string(body), "Hello, World!"))
  1159  	})
  1160  }
  1161  
  1162  // go test -run Test_App_Mixed_Routes_WithSameLen
  1163  func Test_App_Mixed_Routes_WithSameLen(t *testing.T) {
  1164  	t.Parallel()
  1165  	app := New()
  1166  
  1167  	// middleware
  1168  	app.Use(func(c *Ctx) error {
  1169  		c.Set("TestHeader", "TestValue")
  1170  		return c.Next()
  1171  	})
  1172  	// routes with the same length
  1173  	app.Static("/tesbar", "./.github")
  1174  	app.Get("/foobar", func(c *Ctx) error {
  1175  		c.Type("html")
  1176  		return c.Send([]byte("FOO_BAR"))
  1177  	})
  1178  
  1179  	// match get route
  1180  	req := httptest.NewRequest(MethodGet, "/foobar", nil)
  1181  	resp, err := app.Test(req)
  1182  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1183  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1184  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1185  	utils.AssertEqual(t, "TestValue", resp.Header.Get("TestHeader"))
  1186  	utils.AssertEqual(t, "text/html", resp.Header.Get(HeaderContentType))
  1187  
  1188  	body, err := io.ReadAll(resp.Body)
  1189  	utils.AssertEqual(t, nil, err)
  1190  	utils.AssertEqual(t, "FOO_BAR", string(body))
  1191  
  1192  	// match static route
  1193  	req = httptest.NewRequest(MethodGet, "/tesbar", nil)
  1194  	resp, err = app.Test(req)
  1195  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1196  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1197  	utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "")
  1198  	utils.AssertEqual(t, "TestValue", resp.Header.Get("TestHeader"))
  1199  	utils.AssertEqual(t, "text/html; charset=utf-8", resp.Header.Get(HeaderContentType))
  1200  
  1201  	body, err = io.ReadAll(resp.Body)
  1202  	utils.AssertEqual(t, nil, err)
  1203  	utils.AssertEqual(t, true, strings.Contains(string(body), "Hello, World!"), "Response: "+string(body))
  1204  	utils.AssertEqual(t, true, strings.HasPrefix(string(body), "<!DOCTYPE html>"), "Response: "+string(body))
  1205  }
  1206  
  1207  func Test_App_Group_Invalid(t *testing.T) {
  1208  	t.Parallel()
  1209  	defer func() {
  1210  		if err := recover(); err != nil {
  1211  			utils.AssertEqual(t, "use: invalid handler int\n", fmt.Sprintf("%v", err))
  1212  		}
  1213  	}()
  1214  	New().Group("/").Use(1)
  1215  }
  1216  
  1217  func Test_App_Group(t *testing.T) {
  1218  	t.Parallel()
  1219  	dummyHandler := testEmptyHandler
  1220  
  1221  	app := New()
  1222  
  1223  	grp := app.Group("/test")
  1224  	grp.Get("/", dummyHandler)
  1225  	testStatus200(t, app, "/test", MethodGet)
  1226  
  1227  	grp.Get("/:demo?", dummyHandler)
  1228  	testStatus200(t, app, "/test/john", MethodGet)
  1229  
  1230  	grp.Connect("/CONNECT", dummyHandler)
  1231  	testStatus200(t, app, "/test/CONNECT", MethodConnect)
  1232  
  1233  	grp.Put("/PUT", dummyHandler)
  1234  	testStatus200(t, app, "/test/PUT", MethodPut)
  1235  
  1236  	grp.Post("/POST", dummyHandler)
  1237  	testStatus200(t, app, "/test/POST", MethodPost)
  1238  
  1239  	grp.Delete("/DELETE", dummyHandler)
  1240  	testStatus200(t, app, "/test/DELETE", MethodDelete)
  1241  
  1242  	grp.Head("/HEAD", dummyHandler)
  1243  	testStatus200(t, app, "/test/HEAD", MethodHead)
  1244  
  1245  	grp.Patch("/PATCH", dummyHandler)
  1246  	testStatus200(t, app, "/test/PATCH", MethodPatch)
  1247  
  1248  	grp.Options("/OPTIONS", dummyHandler)
  1249  	testStatus200(t, app, "/test/OPTIONS", MethodOptions)
  1250  
  1251  	grp.Trace("/TRACE", dummyHandler)
  1252  	testStatus200(t, app, "/test/TRACE", MethodTrace)
  1253  
  1254  	grp.All("/ALL", dummyHandler)
  1255  	testStatus200(t, app, "/test/ALL", MethodPost)
  1256  
  1257  	grp.Use(dummyHandler)
  1258  	testStatus200(t, app, "/test/oke", MethodGet)
  1259  
  1260  	grp.Use("/USE", dummyHandler)
  1261  	testStatus200(t, app, "/test/USE/oke", MethodGet)
  1262  
  1263  	api := grp.Group("/v1")
  1264  	api.Post("/", dummyHandler)
  1265  
  1266  	resp, err := app.Test(httptest.NewRequest(MethodPost, "/test/v1/", nil))
  1267  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1268  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1269  	// utils.AssertEqual(t, "/test/v1", resp.Header.Get("Location"), "Location")
  1270  
  1271  	api.Get("/users", dummyHandler)
  1272  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test/v1/UsErS", nil))
  1273  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1274  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1275  	// utils.AssertEqual(t, "/test/v1/users", resp.Header.Get("Location"), "Location")
  1276  }
  1277  
  1278  func Test_App_Route(t *testing.T) {
  1279  	t.Parallel()
  1280  	dummyHandler := testEmptyHandler
  1281  
  1282  	app := New()
  1283  
  1284  	grp := app.Route("/test", func(grp Router) {
  1285  		grp.Get("/", dummyHandler)
  1286  		grp.Get("/:demo?", dummyHandler)
  1287  		grp.Connect("/CONNECT", dummyHandler)
  1288  		grp.Put("/PUT", dummyHandler)
  1289  		grp.Post("/POST", dummyHandler)
  1290  		grp.Delete("/DELETE", dummyHandler)
  1291  		grp.Head("/HEAD", dummyHandler)
  1292  		grp.Patch("/PATCH", dummyHandler)
  1293  		grp.Options("/OPTIONS", dummyHandler)
  1294  		grp.Trace("/TRACE", dummyHandler)
  1295  		grp.All("/ALL", dummyHandler)
  1296  		grp.Use(dummyHandler)
  1297  		grp.Use("/USE", dummyHandler)
  1298  	})
  1299  
  1300  	testStatus200(t, app, "/test", MethodGet)
  1301  	testStatus200(t, app, "/test/john", MethodGet)
  1302  	testStatus200(t, app, "/test/CONNECT", MethodConnect)
  1303  	testStatus200(t, app, "/test/PUT", MethodPut)
  1304  	testStatus200(t, app, "/test/POST", MethodPost)
  1305  	testStatus200(t, app, "/test/DELETE", MethodDelete)
  1306  	testStatus200(t, app, "/test/HEAD", MethodHead)
  1307  	testStatus200(t, app, "/test/PATCH", MethodPatch)
  1308  	testStatus200(t, app, "/test/OPTIONS", MethodOptions)
  1309  	testStatus200(t, app, "/test/TRACE", MethodTrace)
  1310  	testStatus200(t, app, "/test/ALL", MethodPost)
  1311  	testStatus200(t, app, "/test/oke", MethodGet)
  1312  	testStatus200(t, app, "/test/USE/oke", MethodGet)
  1313  
  1314  	grp.Route("/v1", func(grp Router) {
  1315  		grp.Post("/", dummyHandler)
  1316  		grp.Get("/users", dummyHandler)
  1317  	})
  1318  
  1319  	resp, err := app.Test(httptest.NewRequest(MethodPost, "/test/v1/", nil))
  1320  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1321  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1322  
  1323  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test/v1/UsErS", nil))
  1324  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1325  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1326  }
  1327  
  1328  func Test_App_Deep_Group(t *testing.T) {
  1329  	t.Parallel()
  1330  	runThroughCount := 0
  1331  	dummyHandler := func(c *Ctx) error {
  1332  		runThroughCount++
  1333  		return c.Next()
  1334  	}
  1335  
  1336  	app := New()
  1337  	gAPI := app.Group("/api", dummyHandler)
  1338  	gV1 := gAPI.Group("/v1", dummyHandler)
  1339  	gUser := gV1.Group("/user", dummyHandler)
  1340  	gUser.Get("/authenticate", func(c *Ctx) error {
  1341  		runThroughCount++
  1342  		return c.SendStatus(200)
  1343  	})
  1344  	testStatus200(t, app, "/api/v1/user/authenticate", MethodGet)
  1345  	utils.AssertEqual(t, 4, runThroughCount, "Loop count")
  1346  }
  1347  
  1348  // go test -run Test_App_Next_Method
  1349  func Test_App_Next_Method(t *testing.T) {
  1350  	t.Parallel()
  1351  	app := New()
  1352  	app.config.DisableStartupMessage = true
  1353  
  1354  	app.Use(func(c *Ctx) error {
  1355  		utils.AssertEqual(t, MethodGet, c.Method())
  1356  		err := c.Next()
  1357  		utils.AssertEqual(t, MethodGet, c.Method())
  1358  		return err
  1359  	})
  1360  
  1361  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
  1362  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1363  	utils.AssertEqual(t, 404, resp.StatusCode, "Status code")
  1364  }
  1365  
  1366  // go test -v -run=^$ -bench=Benchmark_AcquireCtx -benchmem -count=4
  1367  func Benchmark_AcquireCtx(b *testing.B) {
  1368  	app := New()
  1369  	for n := 0; n < b.N; n++ {
  1370  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1371  		app.ReleaseCtx(c)
  1372  	}
  1373  }
  1374  
  1375  // go test -v -run=^$ -bench=Benchmark_App_ETag -benchmem -count=4
  1376  func Benchmark_App_ETag(b *testing.B) {
  1377  	app := New()
  1378  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1379  	defer app.ReleaseCtx(c)
  1380  	err := c.Send([]byte("Hello, World!"))
  1381  	utils.AssertEqual(b, nil, err)
  1382  	for n := 0; n < b.N; n++ {
  1383  		setETag(c, false)
  1384  	}
  1385  	utils.AssertEqual(b, `"13-1831710635"`, string(c.Response().Header.Peek(HeaderETag)))
  1386  }
  1387  
  1388  // go test -v -run=^$ -bench=Benchmark_App_ETag_Weak -benchmem -count=4
  1389  func Benchmark_App_ETag_Weak(b *testing.B) {
  1390  	app := New()
  1391  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1392  	defer app.ReleaseCtx(c)
  1393  	utils.AssertEqual(b, nil, c.Send([]byte("Hello, World!")))
  1394  	for n := 0; n < b.N; n++ {
  1395  		setETag(c, true)
  1396  	}
  1397  	utils.AssertEqual(b, `W/"13-1831710635"`, string(c.Response().Header.Peek(HeaderETag)))
  1398  }
  1399  
  1400  // go test -run Test_NewError
  1401  func Test_NewError(t *testing.T) {
  1402  	t.Parallel()
  1403  	err := NewError(StatusForbidden, "permission denied")
  1404  	utils.AssertEqual(t, StatusForbidden, err.Code)
  1405  	utils.AssertEqual(t, "permission denied", err.Message)
  1406  }
  1407  
  1408  // go test -run Test_Test_Timeout
  1409  func Test_Test_Timeout(t *testing.T) {
  1410  	t.Parallel()
  1411  	app := New()
  1412  	app.config.DisableStartupMessage = true
  1413  
  1414  	app.Get("/", testEmptyHandler)
  1415  
  1416  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), -1)
  1417  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1418  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
  1419  
  1420  	app.Get("timeout", func(c *Ctx) error {
  1421  		time.Sleep(200 * time.Millisecond)
  1422  		return nil
  1423  	})
  1424  
  1425  	_, err = app.Test(httptest.NewRequest(MethodGet, "/timeout", nil), 20)
  1426  	utils.AssertEqual(t, true, err != nil, "app.Test(req)")
  1427  }
  1428  
  1429  type errorReader int
  1430  
  1431  func (errorReader) Read([]byte) (int, error) {
  1432  	return 0, errors.New("errorReader")
  1433  }
  1434  
  1435  // go test -run Test_Test_DumpError
  1436  func Test_Test_DumpError(t *testing.T) {
  1437  	t.Parallel()
  1438  	app := New()
  1439  	app.config.DisableStartupMessage = true
  1440  
  1441  	app.Get("/", testEmptyHandler)
  1442  
  1443  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", errorReader(0)))
  1444  	utils.AssertEqual(t, true, resp == nil)
  1445  	utils.AssertEqual(t, "failed to dump request: errorReader", err.Error())
  1446  }
  1447  
  1448  // go test -run Test_App_Handler
  1449  func Test_App_Handler(t *testing.T) {
  1450  	t.Parallel()
  1451  	h := New().Handler()
  1452  	utils.AssertEqual(t, "fasthttp.RequestHandler", reflect.TypeOf(h).String())
  1453  }
  1454  
  1455  type invalidView struct{}
  1456  
  1457  func (invalidView) Load() error { return errors.New("invalid view") }
  1458  
  1459  func (invalidView) Render(io.Writer, string, interface{}, ...string) error { panic("implement me") }
  1460  
  1461  // go test -run Test_App_Init_Error_View
  1462  func Test_App_Init_Error_View(t *testing.T) {
  1463  	t.Parallel()
  1464  	app := New(Config{Views: invalidView{}})
  1465  
  1466  	defer func() {
  1467  		if err := recover(); err != nil {
  1468  			utils.AssertEqual(t, "implement me", fmt.Sprintf("%v", err))
  1469  		}
  1470  	}()
  1471  
  1472  	err := app.config.Views.Render(nil, "", nil)
  1473  	utils.AssertEqual(t, nil, err)
  1474  }
  1475  
  1476  // go test -run Test_App_Stack
  1477  func Test_App_Stack(t *testing.T) {
  1478  	t.Parallel()
  1479  	app := New()
  1480  
  1481  	app.Use("/path0", testEmptyHandler)
  1482  	app.Get("/path1", testEmptyHandler)
  1483  	app.Get("/path2", testEmptyHandler)
  1484  	app.Post("/path3", testEmptyHandler)
  1485  
  1486  	stack := app.Stack()
  1487  	methodList := app.config.RequestMethods
  1488  	utils.AssertEqual(t, len(methodList), len(stack))
  1489  	utils.AssertEqual(t, 3, len(stack[app.methodInt(MethodGet)]))
  1490  	utils.AssertEqual(t, 3, len(stack[app.methodInt(MethodHead)]))
  1491  	utils.AssertEqual(t, 2, len(stack[app.methodInt(MethodPost)]))
  1492  	utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodPut)]))
  1493  	utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodPatch)]))
  1494  	utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodDelete)]))
  1495  	utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodConnect)]))
  1496  	utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodOptions)]))
  1497  	utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodTrace)]))
  1498  }
  1499  
  1500  // go test -run Test_App_HandlersCount
  1501  func Test_App_HandlersCount(t *testing.T) {
  1502  	t.Parallel()
  1503  	app := New()
  1504  
  1505  	app.Use("/path0", testEmptyHandler)
  1506  	app.Get("/path2", testEmptyHandler)
  1507  	app.Post("/path3", testEmptyHandler)
  1508  
  1509  	count := app.HandlersCount()
  1510  	utils.AssertEqual(t, uint32(4), count)
  1511  }
  1512  
  1513  // go test -run Test_App_ReadTimeout
  1514  func Test_App_ReadTimeout(t *testing.T) {
  1515  	t.Parallel()
  1516  	app := New(Config{
  1517  		ReadTimeout:           time.Nanosecond,
  1518  		IdleTimeout:           time.Minute,
  1519  		DisableStartupMessage: true,
  1520  		DisableKeepalive:      true,
  1521  	})
  1522  
  1523  	app.Get("/read-timeout", func(c *Ctx) error {
  1524  		return c.SendString("I should not be sent")
  1525  	})
  1526  
  1527  	go func() {
  1528  		time.Sleep(500 * time.Millisecond)
  1529  
  1530  		conn, err := net.Dial(NetworkTCP4, "127.0.0.1:4004")
  1531  		utils.AssertEqual(t, nil, err)
  1532  		defer func(conn net.Conn) {
  1533  			err := conn.Close()
  1534  			utils.AssertEqual(t, nil, err)
  1535  		}(conn)
  1536  
  1537  		_, err = conn.Write([]byte("HEAD /read-timeout HTTP/1.1\r\n"))
  1538  		utils.AssertEqual(t, nil, err)
  1539  
  1540  		buf := make([]byte, 1024)
  1541  		var n int
  1542  		n, err = conn.Read(buf)
  1543  
  1544  		utils.AssertEqual(t, nil, err)
  1545  		utils.AssertEqual(t, true, bytes.Contains(buf[:n], []byte("408 Request Timeout")))
  1546  
  1547  		utils.AssertEqual(t, nil, app.Shutdown())
  1548  	}()
  1549  
  1550  	utils.AssertEqual(t, nil, app.Listen(":4004"))
  1551  }
  1552  
  1553  // go test -run Test_App_BadRequest
  1554  func Test_App_BadRequest(t *testing.T) {
  1555  	t.Parallel()
  1556  	app := New(Config{
  1557  		DisableStartupMessage: true,
  1558  	})
  1559  
  1560  	app.Get("/bad-request", func(c *Ctx) error {
  1561  		return c.SendString("I should not be sent")
  1562  	})
  1563  
  1564  	go func() {
  1565  		time.Sleep(500 * time.Millisecond)
  1566  		conn, err := net.Dial(NetworkTCP4, "127.0.0.1:4005")
  1567  		utils.AssertEqual(t, nil, err)
  1568  		defer func(conn net.Conn) {
  1569  			err := conn.Close()
  1570  			utils.AssertEqual(t, nil, err)
  1571  		}(conn)
  1572  
  1573  		_, err = conn.Write([]byte("BadRequest\r\n"))
  1574  		utils.AssertEqual(t, nil, err)
  1575  
  1576  		buf := make([]byte, 1024)
  1577  		var n int
  1578  		n, err = conn.Read(buf)
  1579  		utils.AssertEqual(t, nil, err)
  1580  
  1581  		utils.AssertEqual(t, true, bytes.Contains(buf[:n], []byte("400 Bad Request")))
  1582  
  1583  		utils.AssertEqual(t, nil, app.Shutdown())
  1584  	}()
  1585  
  1586  	utils.AssertEqual(t, nil, app.Listen(":4005"))
  1587  }
  1588  
  1589  // go test -run Test_App_SmallReadBuffer
  1590  func Test_App_SmallReadBuffer(t *testing.T) {
  1591  	t.Parallel()
  1592  	app := New(Config{
  1593  		ReadBufferSize:        1,
  1594  		DisableStartupMessage: true,
  1595  	})
  1596  
  1597  	app.Get("/small-read-buffer", func(c *Ctx) error {
  1598  		return c.SendString("I should not be sent")
  1599  	})
  1600  
  1601  	go func() {
  1602  		time.Sleep(500 * time.Millisecond)
  1603  		req, err := http.NewRequestWithContext(context.Background(), MethodGet, "http://127.0.0.1:4006/small-read-buffer", http.NoBody)
  1604  		utils.AssertEqual(t, nil, err)
  1605  		var client http.Client
  1606  		resp, err := client.Do(req)
  1607  		utils.AssertEqual(t, nil, err)
  1608  		utils.AssertEqual(t, 431, resp.StatusCode)
  1609  		utils.AssertEqual(t, nil, app.Shutdown())
  1610  	}()
  1611  
  1612  	utils.AssertEqual(t, nil, app.Listen(":4006"))
  1613  }
  1614  
  1615  func Test_App_Server(t *testing.T) {
  1616  	t.Parallel()
  1617  	app := New()
  1618  
  1619  	utils.AssertEqual(t, false, app.Server() == nil)
  1620  }
  1621  
  1622  func Test_App_Error_In_Fasthttp_Server(t *testing.T) {
  1623  	t.Parallel()
  1624  	app := New()
  1625  	app.config.ErrorHandler = func(ctx *Ctx, err error) error {
  1626  		return errors.New("fake error")
  1627  	}
  1628  	app.server.GetOnly = true
  1629  
  1630  	resp, err := app.Test(httptest.NewRequest(MethodPost, "/", nil))
  1631  	utils.AssertEqual(t, nil, err)
  1632  	utils.AssertEqual(t, 500, resp.StatusCode)
  1633  }
  1634  
  1635  // go test -race -run Test_App_New_Test_Parallel
  1636  func Test_App_New_Test_Parallel(t *testing.T) {
  1637  	t.Parallel()
  1638  	t.Run("Test_App_New_Test_Parallel_1", func(t *testing.T) {
  1639  		t.Parallel()
  1640  		app := New(Config{Immutable: true})
  1641  		_, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
  1642  		utils.AssertEqual(t, nil, err)
  1643  	})
  1644  	t.Run("Test_App_New_Test_Parallel_2", func(t *testing.T) {
  1645  		t.Parallel()
  1646  		app := New(Config{Immutable: true})
  1647  		_, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
  1648  		utils.AssertEqual(t, nil, err)
  1649  	})
  1650  }
  1651  
  1652  func Test_App_ReadBodyStream(t *testing.T) {
  1653  	t.Parallel()
  1654  	app := New(Config{StreamRequestBody: true})
  1655  	app.Post("/", func(c *Ctx) error {
  1656  		// Calling c.Body() automatically reads the entire stream.
  1657  		return c.SendString(fmt.Sprintf("%v %s", c.Request().IsBodyStream(), c.Body()))
  1658  	})
  1659  	testString := "this is a test"
  1660  	resp, err := app.Test(httptest.NewRequest(MethodPost, "/", bytes.NewBufferString(testString)))
  1661  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1662  	body, err := io.ReadAll(resp.Body)
  1663  	utils.AssertEqual(t, nil, err, "io.ReadAll(resp.Body)")
  1664  	utils.AssertEqual(t, fmt.Sprintf("true %s", testString), string(body))
  1665  }
  1666  
  1667  func Test_App_DisablePreParseMultipartForm(t *testing.T) {
  1668  	t.Parallel()
  1669  	// Must be used with both otherwise there is no point.
  1670  	testString := "this is a test"
  1671  
  1672  	app := New(Config{DisablePreParseMultipartForm: true, StreamRequestBody: true})
  1673  	app.Post("/", func(c *Ctx) error {
  1674  		req := c.Request()
  1675  		mpf, err := req.MultipartForm()
  1676  		if err != nil {
  1677  			return err
  1678  		}
  1679  		if !req.IsBodyStream() {
  1680  			return fmt.Errorf("not a body stream")
  1681  		}
  1682  		file, err := mpf.File["test"][0].Open()
  1683  		if err != nil {
  1684  			return fmt.Errorf("failed to open: %w", err)
  1685  		}
  1686  		buffer := make([]byte, len(testString))
  1687  		n, err := file.Read(buffer)
  1688  		if err != nil {
  1689  			return fmt.Errorf("failed to read: %w", err)
  1690  		}
  1691  		if n != len(testString) {
  1692  			return fmt.Errorf("bad read length")
  1693  		}
  1694  		return c.Send(buffer)
  1695  	})
  1696  	b := &bytes.Buffer{}
  1697  	w := multipart.NewWriter(b)
  1698  	writer, err := w.CreateFormFile("test", "test")
  1699  	utils.AssertEqual(t, nil, err, "w.CreateFormFile")
  1700  	n, err := writer.Write([]byte(testString))
  1701  	utils.AssertEqual(t, nil, err, "writer.Write")
  1702  	utils.AssertEqual(t, len(testString), n, "writer n")
  1703  	utils.AssertEqual(t, nil, w.Close(), "w.Close()")
  1704  
  1705  	req := httptest.NewRequest(MethodPost, "/", b)
  1706  	req.Header.Set("Content-Type", w.FormDataContentType())
  1707  	resp, err := app.Test(req)
  1708  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1709  	body, err := io.ReadAll(resp.Body)
  1710  	utils.AssertEqual(t, nil, err, "io.ReadAll(resp.Body)")
  1711  
  1712  	utils.AssertEqual(t, testString, string(body))
  1713  }
  1714  
  1715  func Test_App_Test_no_timeout_infinitely(t *testing.T) {
  1716  	t.Parallel()
  1717  	var err error
  1718  	c := make(chan int)
  1719  
  1720  	go func() {
  1721  		defer func() { c <- 0 }()
  1722  		app := New()
  1723  		app.Get("/", func(c *Ctx) error {
  1724  			runtime.Goexit()
  1725  			return nil
  1726  		})
  1727  
  1728  		req := httptest.NewRequest(MethodGet, "/", http.NoBody)
  1729  		_, err = app.Test(req, -1)
  1730  	}()
  1731  
  1732  	tk := time.NewTimer(5 * time.Second)
  1733  	defer tk.Stop()
  1734  
  1735  	select {
  1736  	case <-tk.C:
  1737  		t.Error("hanging test")
  1738  		t.FailNow()
  1739  	case <-c:
  1740  	}
  1741  
  1742  	if err == nil {
  1743  		t.Error("unexpected success request")
  1744  		t.FailNow()
  1745  	}
  1746  }
  1747  
  1748  func Test_App_SetTLSHandler(t *testing.T) {
  1749  	t.Parallel()
  1750  	tlsHandler := &TLSHandler{clientHelloInfo: &tls.ClientHelloInfo{
  1751  		ServerName: "example.golang",
  1752  	}}
  1753  
  1754  	app := New()
  1755  	app.SetTLSHandler(tlsHandler)
  1756  
  1757  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1758  	defer app.ReleaseCtx(c)
  1759  
  1760  	utils.AssertEqual(t, "example.golang", c.ClientHelloInfo().ServerName)
  1761  }
  1762  
  1763  func Test_App_AddCustomRequestMethod(t *testing.T) {
  1764  	t.Parallel()
  1765  	methods := append(DefaultMethods, "TEST") //nolint:gocritic // We want a new slice here
  1766  	app := New(Config{
  1767  		RequestMethods: methods,
  1768  	})
  1769  	appMethods := app.config.RequestMethods
  1770  
  1771  	// method name is always uppercase - https://datatracker.ietf.org/doc/html/rfc7231#section-4.1
  1772  	utils.AssertEqual(t, len(app.stack), len(appMethods))
  1773  	utils.AssertEqual(t, len(app.stack), len(appMethods))
  1774  	utils.AssertEqual(t, "TEST", appMethods[len(appMethods)-1])
  1775  }
  1776  
  1777  func TestApp_GetRoutes(t *testing.T) {
  1778  	t.Parallel()
  1779  	app := New()
  1780  	app.Use(func(c *Ctx) error {
  1781  		return c.Next()
  1782  	})
  1783  	handler := func(c *Ctx) error {
  1784  		return c.SendStatus(StatusOK)
  1785  	}
  1786  	app.Delete("/delete", handler).Name("delete")
  1787  	app.Post("/post", handler).Name("post")
  1788  	routes := app.GetRoutes(false)
  1789  	utils.AssertEqual(t, 2+len(app.config.RequestMethods), len(routes))
  1790  	methodMap := map[string]string{"/delete": "delete", "/post": "post"}
  1791  	for _, route := range routes {
  1792  		name, ok := methodMap[route.Path]
  1793  		if ok {
  1794  			utils.AssertEqual(t, name, route.Name)
  1795  		}
  1796  	}
  1797  
  1798  	routes = app.GetRoutes(true)
  1799  	utils.AssertEqual(t, 2, len(routes))
  1800  	for _, route := range routes {
  1801  		name, ok := methodMap[route.Path]
  1802  		utils.AssertEqual(t, true, ok)
  1803  		utils.AssertEqual(t, name, route.Name)
  1804  	}
  1805  }
  1806  
  1807  func Test_Middleware_Route_Naming_With_Use(t *testing.T) {
  1808  	named := "named"
  1809  	app := New()
  1810  
  1811  	app.Get("/unnamed", func(c *Ctx) error {
  1812  		return c.Next()
  1813  	})
  1814  
  1815  	app.Post("/named", func(c *Ctx) error {
  1816  		return c.Next()
  1817  	}).Name(named)
  1818  
  1819  	app.Use(func(c *Ctx) error {
  1820  		return c.Next()
  1821  	}) // no name - logging MW
  1822  
  1823  	app.Use(func(c *Ctx) error {
  1824  		return c.Next()
  1825  	}).Name("corsMW")
  1826  
  1827  	app.Use(func(c *Ctx) error {
  1828  		return c.Next()
  1829  	}).Name("compressMW")
  1830  
  1831  	app.Use(func(c *Ctx) error {
  1832  		return c.Next()
  1833  	}) // no name - cache MW
  1834  
  1835  	grp := app.Group("/pages").Name("pages.")
  1836  	grp.Use(func(c *Ctx) error {
  1837  		return c.Next()
  1838  	}).Name("csrfMW")
  1839  
  1840  	grp.Get("/home", func(c *Ctx) error {
  1841  		return c.Next()
  1842  	}).Name("home")
  1843  
  1844  	grp.Get("/unnamed", func(c *Ctx) error {
  1845  		return c.Next()
  1846  	})
  1847  
  1848  	for _, route := range app.GetRoutes() {
  1849  		switch route.Path {
  1850  		case "/":
  1851  			utils.AssertEqual(t, "compressMW", route.Name)
  1852  		case "/unnamed":
  1853  			utils.AssertEqual(t, "", route.Name)
  1854  		case "named":
  1855  			utils.AssertEqual(t, named, route.Name)
  1856  		case "/pages":
  1857  			utils.AssertEqual(t, "pages.csrfMW", route.Name)
  1858  		case "/pages/home":
  1859  			utils.AssertEqual(t, "pages.home", route.Name)
  1860  		case "/pages/unnamed":
  1861  			utils.AssertEqual(t, "", route.Name)
  1862  		}
  1863  	}
  1864  }