github.com/gofiber/fiber/v2@v2.47.0/router_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  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"net/http/httptest"
    14  	"os"
    15  	"strings"
    16  	"testing"
    17  
    18  	"github.com/gofiber/fiber/v2/utils"
    19  
    20  	"github.com/valyala/fasthttp"
    21  )
    22  
    23  var routesFixture routeJSON
    24  
    25  func init() {
    26  	dat, err := os.ReadFile("./.github/testdata/testRoutes.json")
    27  	if err != nil {
    28  		panic(err)
    29  	}
    30  	if err := json.Unmarshal(dat, &routesFixture); err != nil {
    31  		panic(err)
    32  	}
    33  }
    34  
    35  func Test_Route_Match_SameLength(t *testing.T) {
    36  	t.Parallel()
    37  
    38  	app := New()
    39  
    40  	app.Get("/:param", func(c *Ctx) error {
    41  		return c.SendString(c.Params("param"))
    42  	})
    43  
    44  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/:param", nil))
    45  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    46  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
    47  
    48  	body, err := io.ReadAll(resp.Body)
    49  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    50  	utils.AssertEqual(t, ":param", app.getString(body))
    51  
    52  	// with param
    53  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test", nil))
    54  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    55  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
    56  
    57  	body, err = io.ReadAll(resp.Body)
    58  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    59  	utils.AssertEqual(t, "test", app.getString(body))
    60  }
    61  
    62  func Test_Route_Match_Star(t *testing.T) {
    63  	t.Parallel()
    64  
    65  	app := New()
    66  
    67  	app.Get("/*", func(c *Ctx) error {
    68  		return c.SendString(c.Params("*"))
    69  	})
    70  
    71  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/*", nil))
    72  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    73  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
    74  
    75  	body, err := io.ReadAll(resp.Body)
    76  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    77  	utils.AssertEqual(t, "*", app.getString(body))
    78  
    79  	// with param
    80  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test", nil))
    81  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    82  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
    83  
    84  	body, err = io.ReadAll(resp.Body)
    85  	utils.AssertEqual(t, nil, err, "app.Test(req)")
    86  	utils.AssertEqual(t, "test", app.getString(body))
    87  
    88  	// without parameter
    89  	route := Route{
    90  		star:        true,
    91  		path:        "/*",
    92  		routeParser: routeParser{},
    93  	}
    94  	params := [maxParams]string{}
    95  	match := route.match("", "", &params)
    96  	utils.AssertEqual(t, true, match)
    97  	utils.AssertEqual(t, [maxParams]string{}, params)
    98  
    99  	// with parameter
   100  	match = route.match("/favicon.ico", "/favicon.ico", &params)
   101  	utils.AssertEqual(t, true, match)
   102  	utils.AssertEqual(t, [maxParams]string{"favicon.ico"}, params)
   103  
   104  	// without parameter again
   105  	match = route.match("", "", &params)
   106  	utils.AssertEqual(t, true, match)
   107  	utils.AssertEqual(t, [maxParams]string{}, params)
   108  }
   109  
   110  func Test_Route_Match_Root(t *testing.T) {
   111  	t.Parallel()
   112  
   113  	app := New()
   114  
   115  	app.Get("/", func(c *Ctx) error {
   116  		return c.SendString("root")
   117  	})
   118  
   119  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
   120  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   121  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   122  
   123  	body, err := io.ReadAll(resp.Body)
   124  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   125  	utils.AssertEqual(t, "root", app.getString(body))
   126  }
   127  
   128  func Test_Route_Match_Parser(t *testing.T) {
   129  	t.Parallel()
   130  
   131  	app := New()
   132  
   133  	app.Get("/foo/:ParamName", func(c *Ctx) error {
   134  		return c.SendString(c.Params("ParamName"))
   135  	})
   136  	app.Get("/Foobar/*", func(c *Ctx) error {
   137  		return c.SendString(c.Params("*"))
   138  	})
   139  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/foo/bar", nil))
   140  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   141  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   142  
   143  	body, err := io.ReadAll(resp.Body)
   144  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   145  	utils.AssertEqual(t, "bar", app.getString(body))
   146  
   147  	// with star
   148  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/Foobar/test", nil))
   149  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   150  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   151  
   152  	body, err = io.ReadAll(resp.Body)
   153  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   154  	utils.AssertEqual(t, "test", app.getString(body))
   155  }
   156  
   157  func Test_Route_Match_Middleware(t *testing.T) {
   158  	t.Parallel()
   159  
   160  	app := New()
   161  
   162  	app.Use("/foo/*", func(c *Ctx) error {
   163  		return c.SendString(c.Params("*"))
   164  	})
   165  
   166  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/foo/*", nil))
   167  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   168  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   169  
   170  	body, err := io.ReadAll(resp.Body)
   171  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   172  	utils.AssertEqual(t, "*", app.getString(body))
   173  
   174  	// with param
   175  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/foo/bar/fasel", nil))
   176  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   177  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   178  
   179  	body, err = io.ReadAll(resp.Body)
   180  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   181  	utils.AssertEqual(t, "bar/fasel", app.getString(body))
   182  }
   183  
   184  func Test_Route_Match_UnescapedPath(t *testing.T) {
   185  	t.Parallel()
   186  
   187  	app := New(Config{UnescapePath: true})
   188  
   189  	app.Use("/créer", func(c *Ctx) error {
   190  		return c.SendString("test")
   191  	})
   192  
   193  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/cr%C3%A9er", nil))
   194  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   195  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   196  
   197  	body, err := io.ReadAll(resp.Body)
   198  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   199  	utils.AssertEqual(t, "test", app.getString(body))
   200  	// without special chars
   201  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/créer", nil))
   202  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   203  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   204  
   205  	// check deactivated behavior
   206  	app.config.UnescapePath = false
   207  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/cr%C3%A9er", nil))
   208  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   209  	utils.AssertEqual(t, StatusNotFound, resp.StatusCode, "Status code")
   210  }
   211  
   212  func Test_Route_Match_WithEscapeChar(t *testing.T) {
   213  	t.Parallel()
   214  
   215  	app := New()
   216  	// static route and escaped part
   217  	app.Get("/v1/some/resource/name\\:customVerb", func(c *Ctx) error {
   218  		return c.SendString("static")
   219  	})
   220  	// group route
   221  	group := app.Group("/v2/\\:firstVerb")
   222  	group.Get("/\\:customVerb", func(c *Ctx) error {
   223  		return c.SendString("group")
   224  	})
   225  	// route with resource param and escaped part
   226  	app.Get("/v3/:resource/name\\:customVerb", func(c *Ctx) error {
   227  		return c.SendString(c.Params("resource"))
   228  	})
   229  
   230  	// check static route
   231  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/v1/some/resource/name:customVerb", nil))
   232  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   233  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   234  
   235  	body, err := io.ReadAll(resp.Body)
   236  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   237  	utils.AssertEqual(t, "static", app.getString(body))
   238  
   239  	// check group route
   240  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/v2/:firstVerb/:customVerb", nil))
   241  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   242  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   243  
   244  	body, err = io.ReadAll(resp.Body)
   245  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   246  	utils.AssertEqual(t, "group", app.getString(body))
   247  
   248  	// check param route
   249  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/v3/awesome/name:customVerb", nil))
   250  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   251  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   252  
   253  	body, err = io.ReadAll(resp.Body)
   254  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   255  	utils.AssertEqual(t, "awesome", app.getString(body))
   256  }
   257  
   258  func Test_Route_Match_Middleware_HasPrefix(t *testing.T) {
   259  	t.Parallel()
   260  
   261  	app := New()
   262  
   263  	app.Use("/foo", func(c *Ctx) error {
   264  		return c.SendString("middleware")
   265  	})
   266  
   267  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/foo/bar", nil))
   268  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   269  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   270  
   271  	body, err := io.ReadAll(resp.Body)
   272  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   273  	utils.AssertEqual(t, "middleware", app.getString(body))
   274  }
   275  
   276  func Test_Route_Match_Middleware_Root(t *testing.T) {
   277  	t.Parallel()
   278  
   279  	app := New()
   280  
   281  	app.Use("/", func(c *Ctx) error {
   282  		return c.SendString("middleware")
   283  	})
   284  
   285  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/everything", nil))
   286  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   287  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   288  
   289  	body, err := io.ReadAll(resp.Body)
   290  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   291  	utils.AssertEqual(t, "middleware", app.getString(body))
   292  }
   293  
   294  func Test_Router_Register_Missing_Handler(t *testing.T) {
   295  	t.Parallel()
   296  
   297  	app := New()
   298  	defer func() {
   299  		if err := recover(); err != nil {
   300  			utils.AssertEqual(t, "missing handler in route: /doe\n", fmt.Sprintf("%v", err))
   301  		}
   302  	}()
   303  	app.register("USE", "/doe", nil)
   304  }
   305  
   306  func Test_Ensure_Router_Interface_Implementation(t *testing.T) {
   307  	t.Parallel()
   308  
   309  	var app interface{} = (*App)(nil)
   310  	_, ok := app.(Router)
   311  	utils.AssertEqual(t, true, ok)
   312  
   313  	var group interface{} = (*Group)(nil)
   314  	_, ok = group.(Router)
   315  	utils.AssertEqual(t, true, ok)
   316  }
   317  
   318  func Test_Router_Handler_SetETag(t *testing.T) {
   319  	t.Parallel()
   320  
   321  	app := New()
   322  	app.config.ETag = true
   323  
   324  	app.Get("/", func(c *Ctx) error {
   325  		return c.SendString("Hello, World!")
   326  	})
   327  
   328  	c := &fasthttp.RequestCtx{}
   329  
   330  	app.Handler()(c)
   331  
   332  	utils.AssertEqual(t, `"13-1831710635"`, string(c.Response.Header.Peek(HeaderETag)))
   333  }
   334  
   335  func Test_Router_Handler_Catch_Error(t *testing.T) {
   336  	t.Parallel()
   337  
   338  	app := New()
   339  	app.config.ErrorHandler = func(ctx *Ctx, err error) error {
   340  		return errors.New("fake error")
   341  	}
   342  
   343  	app.Get("/", func(c *Ctx) error {
   344  		return ErrForbidden
   345  	})
   346  
   347  	c := &fasthttp.RequestCtx{}
   348  
   349  	app.Handler()(c)
   350  
   351  	utils.AssertEqual(t, StatusInternalServerError, c.Response.Header.StatusCode())
   352  }
   353  
   354  func Test_Route_Static_Root(t *testing.T) {
   355  	t.Parallel()
   356  
   357  	dir := "./.github/testdata/fs/css"
   358  	app := New()
   359  	app.Static("/", dir, Static{
   360  		Browse: true,
   361  	})
   362  
   363  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
   364  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   365  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   366  
   367  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/style.css", nil))
   368  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   369  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   370  
   371  	body, err := io.ReadAll(resp.Body)
   372  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   373  	utils.AssertEqual(t, true, strings.Contains(app.getString(body), "color"))
   374  
   375  	app = New()
   376  	app.Static("/", dir)
   377  
   378  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/", nil))
   379  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   380  	utils.AssertEqual(t, 404, resp.StatusCode, "Status code")
   381  
   382  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/style.css", nil))
   383  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   384  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   385  
   386  	body, err = io.ReadAll(resp.Body)
   387  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   388  	utils.AssertEqual(t, true, strings.Contains(app.getString(body), "color"))
   389  }
   390  
   391  func Test_Route_Static_HasPrefix(t *testing.T) {
   392  	t.Parallel()
   393  
   394  	dir := "./.github/testdata/fs/css"
   395  	app := New()
   396  	app.Static("/static", dir, Static{
   397  		Browse: true,
   398  	})
   399  
   400  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/static", nil))
   401  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   402  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   403  
   404  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static/", nil))
   405  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   406  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   407  
   408  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static/style.css", nil))
   409  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   410  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   411  
   412  	body, err := io.ReadAll(resp.Body)
   413  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   414  	utils.AssertEqual(t, true, strings.Contains(app.getString(body), "color"))
   415  
   416  	app = New()
   417  	app.Static("/static/", dir, Static{
   418  		Browse: true,
   419  	})
   420  
   421  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static", nil))
   422  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   423  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   424  
   425  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static/", nil))
   426  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   427  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   428  
   429  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static/style.css", nil))
   430  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   431  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   432  
   433  	body, err = io.ReadAll(resp.Body)
   434  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   435  	utils.AssertEqual(t, true, strings.Contains(app.getString(body), "color"))
   436  
   437  	app = New()
   438  	app.Static("/static", dir)
   439  
   440  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static", nil))
   441  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   442  	utils.AssertEqual(t, 404, resp.StatusCode, "Status code")
   443  
   444  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static/", nil))
   445  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   446  	utils.AssertEqual(t, 404, resp.StatusCode, "Status code")
   447  
   448  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static/style.css", nil))
   449  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   450  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   451  
   452  	body, err = io.ReadAll(resp.Body)
   453  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   454  	utils.AssertEqual(t, true, strings.Contains(app.getString(body), "color"))
   455  
   456  	app = New()
   457  	app.Static("/static/", dir)
   458  
   459  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static", nil))
   460  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   461  	utils.AssertEqual(t, 404, resp.StatusCode, "Status code")
   462  
   463  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static/", nil))
   464  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   465  	utils.AssertEqual(t, 404, resp.StatusCode, "Status code")
   466  
   467  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/static/style.css", nil))
   468  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   469  	utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
   470  
   471  	body, err = io.ReadAll(resp.Body)
   472  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   473  	utils.AssertEqual(t, true, strings.Contains(app.getString(body), "color"))
   474  }
   475  
   476  //////////////////////////////////////////////
   477  ///////////////// BENCHMARKS /////////////////
   478  //////////////////////////////////////////////
   479  
   480  func registerDummyRoutes(app *App) {
   481  	h := func(c *Ctx) error {
   482  		return nil
   483  	}
   484  	for _, r := range routesFixture.GithubAPI {
   485  		app.Add(r.Method, r.Path, h)
   486  	}
   487  }
   488  
   489  // go test -v -run=^$ -bench=Benchmark_App_MethodNotAllowed -benchmem -count=4
   490  func Benchmark_App_MethodNotAllowed(b *testing.B) {
   491  	app := New()
   492  	h := func(c *Ctx) error {
   493  		return c.SendString("Hello World!")
   494  	}
   495  	app.All("/this/is/a/", h)
   496  	app.Get("/this/is/a/dummy/route/oke", h)
   497  	appHandler := app.Handler()
   498  	c := &fasthttp.RequestCtx{}
   499  
   500  	c.Request.Header.SetMethod("DELETE")
   501  	c.URI().SetPath("/this/is/a/dummy/route/oke")
   502  
   503  	b.ResetTimer()
   504  	for n := 0; n < b.N; n++ {
   505  		appHandler(c)
   506  	}
   507  	b.StopTimer()
   508  	utils.AssertEqual(b, 405, c.Response.StatusCode())
   509  	utils.AssertEqual(b, "GET, HEAD", string(c.Response.Header.Peek("Allow")))
   510  	utils.AssertEqual(b, utils.StatusMessage(StatusMethodNotAllowed), string(c.Response.Body()))
   511  }
   512  
   513  // go test -v ./... -run=^$ -bench=Benchmark_Router_NotFound -benchmem -count=4
   514  func Benchmark_Router_NotFound(b *testing.B) {
   515  	app := New()
   516  	app.Use(func(c *Ctx) error {
   517  		return c.Next()
   518  	})
   519  	registerDummyRoutes(app)
   520  	appHandler := app.Handler()
   521  	c := &fasthttp.RequestCtx{}
   522  
   523  	c.Request.Header.SetMethod("DELETE")
   524  	c.URI().SetPath("/this/route/does/not/exist")
   525  
   526  	b.ResetTimer()
   527  	for n := 0; n < b.N; n++ {
   528  		appHandler(c)
   529  	}
   530  	utils.AssertEqual(b, 404, c.Response.StatusCode())
   531  	utils.AssertEqual(b, "Cannot DELETE /this/route/does/not/exist", string(c.Response.Body()))
   532  }
   533  
   534  // go test -v ./... -run=^$ -bench=Benchmark_Router_Handler -benchmem -count=4
   535  func Benchmark_Router_Handler(b *testing.B) {
   536  	app := New()
   537  	registerDummyRoutes(app)
   538  	appHandler := app.Handler()
   539  
   540  	c := &fasthttp.RequestCtx{}
   541  
   542  	c.Request.Header.SetMethod("DELETE")
   543  	c.URI().SetPath("/user/keys/1337")
   544  
   545  	b.ResetTimer()
   546  
   547  	for n := 0; n < b.N; n++ {
   548  		appHandler(c)
   549  	}
   550  }
   551  
   552  func Benchmark_Router_Handler_Strict_Case(b *testing.B) {
   553  	app := New(Config{
   554  		StrictRouting: true,
   555  		CaseSensitive: true,
   556  	})
   557  	registerDummyRoutes(app)
   558  	appHandler := app.Handler()
   559  
   560  	c := &fasthttp.RequestCtx{}
   561  
   562  	c.Request.Header.SetMethod("DELETE")
   563  	c.URI().SetPath("/user/keys/1337")
   564  
   565  	b.ResetTimer()
   566  
   567  	for n := 0; n < b.N; n++ {
   568  		appHandler(c)
   569  	}
   570  }
   571  
   572  // go test -v ./... -run=^$ -bench=Benchmark_Router_Chain -benchmem -count=4
   573  func Benchmark_Router_Chain(b *testing.B) {
   574  	app := New()
   575  	handler := func(c *Ctx) error {
   576  		return c.Next()
   577  	}
   578  	app.Get("/", handler, handler, handler, handler, handler, handler)
   579  
   580  	appHandler := app.Handler()
   581  
   582  	c := &fasthttp.RequestCtx{}
   583  
   584  	c.Request.Header.SetMethod(MethodGet)
   585  	c.URI().SetPath("/")
   586  	b.ResetTimer()
   587  	for n := 0; n < b.N; n++ {
   588  		appHandler(c)
   589  	}
   590  }
   591  
   592  // go test -v ./... -run=^$ -bench=Benchmark_Router_WithCompression -benchmem -count=4
   593  func Benchmark_Router_WithCompression(b *testing.B) {
   594  	app := New()
   595  	handler := func(c *Ctx) error {
   596  		return c.Next()
   597  	}
   598  	app.Get("/", handler)
   599  	app.Get("/", handler)
   600  	app.Get("/", handler)
   601  	app.Get("/", handler)
   602  	app.Get("/", handler)
   603  	app.Get("/", handler)
   604  
   605  	appHandler := app.Handler()
   606  	c := &fasthttp.RequestCtx{}
   607  
   608  	c.Request.Header.SetMethod(MethodGet)
   609  	c.URI().SetPath("/")
   610  	b.ResetTimer()
   611  	for n := 0; n < b.N; n++ {
   612  		appHandler(c)
   613  	}
   614  }
   615  
   616  // go test -run=^$ -bench=Benchmark_Startup_Process -benchmem -count=9
   617  func Benchmark_Startup_Process(b *testing.B) {
   618  	for n := 0; n < b.N; n++ {
   619  		app := New()
   620  		registerDummyRoutes(app)
   621  		app.startupProcess()
   622  	}
   623  }
   624  
   625  // go test -v ./... -run=^$ -bench=Benchmark_Router_Next -benchmem -count=4
   626  func Benchmark_Router_Next(b *testing.B) {
   627  	app := New()
   628  	registerDummyRoutes(app)
   629  	app.startupProcess()
   630  
   631  	request := &fasthttp.RequestCtx{}
   632  
   633  	request.Request.Header.SetMethod("DELETE")
   634  	request.URI().SetPath("/user/keys/1337")
   635  	var res bool
   636  	var err error
   637  
   638  	c := app.AcquireCtx(request)
   639  	defer app.ReleaseCtx(c)
   640  
   641  	b.ResetTimer()
   642  	for n := 0; n < b.N; n++ {
   643  		c.indexRoute = -1
   644  		res, err = app.next(c)
   645  	}
   646  	utils.AssertEqual(b, nil, err)
   647  	utils.AssertEqual(b, true, res)
   648  	utils.AssertEqual(b, 4, c.indexRoute)
   649  }
   650  
   651  // go test -v ./... -run=^$ -bench=Benchmark_Route_Match -benchmem -count=4
   652  func Benchmark_Route_Match(b *testing.B) {
   653  	var match bool
   654  	var params [maxParams]string
   655  
   656  	parsed := parseRoute("/user/keys/:id")
   657  	route := &Route{
   658  		use:         false,
   659  		root:        false,
   660  		star:        false,
   661  		routeParser: parsed,
   662  		Params:      parsed.params,
   663  		path:        "/user/keys/:id",
   664  
   665  		Path:   "/user/keys/:id",
   666  		Method: "DELETE",
   667  	}
   668  	route.Handlers = append(route.Handlers, func(c *Ctx) error {
   669  		return nil
   670  	})
   671  	b.ResetTimer()
   672  	for n := 0; n < b.N; n++ {
   673  		match = route.match("/user/keys/1337", "/user/keys/1337", &params)
   674  	}
   675  
   676  	utils.AssertEqual(b, true, match)
   677  	utils.AssertEqual(b, []string{"1337"}, params[0:len(parsed.params)])
   678  }
   679  
   680  // go test -v ./... -run=^$ -bench=Benchmark_Route_Match_Star -benchmem -count=4
   681  func Benchmark_Route_Match_Star(b *testing.B) {
   682  	var match bool
   683  	var params [maxParams]string
   684  
   685  	parsed := parseRoute("/*")
   686  	route := &Route{
   687  		use:         false,
   688  		root:        false,
   689  		star:        true,
   690  		routeParser: parsed,
   691  		Params:      parsed.params,
   692  		path:        "/user/keys/bla",
   693  
   694  		Path:   "/user/keys/bla",
   695  		Method: "DELETE",
   696  	}
   697  	route.Handlers = append(route.Handlers, func(c *Ctx) error {
   698  		return nil
   699  	})
   700  	b.ResetTimer()
   701  
   702  	for n := 0; n < b.N; n++ {
   703  		match = route.match("/user/keys/bla", "/user/keys/bla", &params)
   704  	}
   705  
   706  	utils.AssertEqual(b, true, match)
   707  	utils.AssertEqual(b, []string{"user/keys/bla"}, params[0:len(parsed.params)])
   708  }
   709  
   710  // go test -v ./... -run=^$ -bench=Benchmark_Route_Match_Root -benchmem -count=4
   711  func Benchmark_Route_Match_Root(b *testing.B) {
   712  	var match bool
   713  	var params [maxParams]string
   714  
   715  	parsed := parseRoute("/")
   716  	route := &Route{
   717  		use:         false,
   718  		root:        true,
   719  		star:        false,
   720  		path:        "/",
   721  		routeParser: parsed,
   722  		Params:      parsed.params,
   723  
   724  		Path:   "/",
   725  		Method: "DELETE",
   726  	}
   727  	route.Handlers = append(route.Handlers, func(c *Ctx) error {
   728  		return nil
   729  	})
   730  
   731  	b.ResetTimer()
   732  
   733  	for n := 0; n < b.N; n++ {
   734  		match = route.match("/", "/", &params)
   735  	}
   736  
   737  	utils.AssertEqual(b, true, match)
   738  	utils.AssertEqual(b, []string{}, params[0:len(parsed.params)])
   739  }
   740  
   741  // go test -v ./... -run=^$ -bench=Benchmark_Router_Handler_CaseSensitive -benchmem -count=4
   742  func Benchmark_Router_Handler_CaseSensitive(b *testing.B) {
   743  	app := New()
   744  	app.config.CaseSensitive = true
   745  	registerDummyRoutes(app)
   746  	appHandler := app.Handler()
   747  
   748  	c := &fasthttp.RequestCtx{}
   749  
   750  	c.Request.Header.SetMethod("DELETE")
   751  	c.URI().SetPath("/user/keys/1337")
   752  
   753  	b.ResetTimer()
   754  
   755  	for n := 0; n < b.N; n++ {
   756  		appHandler(c)
   757  	}
   758  }
   759  
   760  // go test -v ./... -run=^$ -bench=Benchmark_Router_Handler_Unescape -benchmem -count=4
   761  func Benchmark_Router_Handler_Unescape(b *testing.B) {
   762  	app := New()
   763  	app.config.UnescapePath = true
   764  	registerDummyRoutes(app)
   765  	app.Delete("/créer", func(c *Ctx) error {
   766  		return nil
   767  	})
   768  
   769  	appHandler := app.Handler()
   770  
   771  	c := &fasthttp.RequestCtx{}
   772  
   773  	c.Request.Header.SetMethod(MethodDelete)
   774  	c.URI().SetPath("/cr%C3%A9er")
   775  
   776  	b.ResetTimer()
   777  
   778  	for n := 0; n < b.N; n++ {
   779  		c.URI().SetPath("/cr%C3%A9er")
   780  		appHandler(c)
   781  	}
   782  }
   783  
   784  // go test -run=^$ -bench=Benchmark_Router_Handler_StrictRouting -benchmem -count=4
   785  func Benchmark_Router_Handler_StrictRouting(b *testing.B) {
   786  	app := New()
   787  	app.config.CaseSensitive = true
   788  	registerDummyRoutes(app)
   789  	appHandler := app.Handler()
   790  
   791  	c := &fasthttp.RequestCtx{}
   792  
   793  	c.Request.Header.SetMethod("DELETE")
   794  	c.URI().SetPath("/user/keys/1337")
   795  
   796  	b.ResetTimer()
   797  
   798  	for n := 0; n < b.N; n++ {
   799  		appHandler(c)
   800  	}
   801  }
   802  
   803  // go test -run=^$ -bench=Benchmark_Router_Github_API -benchmem -count=16
   804  func Benchmark_Router_Github_API(b *testing.B) {
   805  	app := New()
   806  	registerDummyRoutes(app)
   807  	app.startupProcess()
   808  
   809  	c := &fasthttp.RequestCtx{}
   810  	var match bool
   811  	var err error
   812  
   813  	b.ResetTimer()
   814  
   815  	for i := range routesFixture.TestRoutes {
   816  		c.Request.Header.SetMethod(routesFixture.TestRoutes[i].Method)
   817  		for n := 0; n < b.N; n++ {
   818  			c.URI().SetPath(routesFixture.TestRoutes[i].Path)
   819  			ctx := app.AcquireCtx(c)
   820  			match, err = app.next(ctx)
   821  			app.ReleaseCtx(ctx)
   822  		}
   823  		utils.AssertEqual(b, nil, err)
   824  		utils.AssertEqual(b, true, match)
   825  	}
   826  }
   827  
   828  type testRoute struct {
   829  	Method string `json:"method"`
   830  	Path   string `json:"path"`
   831  }
   832  
   833  type routeJSON struct {
   834  	TestRoutes []testRoute `json:"test_routes"`
   835  	GithubAPI  []testRoute `json:"github_api"`
   836  }