github.com/gramework/gramework@v1.8.1-0.20231027140105-82555c9057f5/fasthttprouter_router_test.go (about)

     1  // Copyright 2013 Julien Schmidt. All rights reserved.
     2  // Copyright (c) 2015-2016, 招牌疯子
     3  // Copyright (c) 2017, Kirill Danshin
     4  // Use of this source code is governed by a BSD-style license that can be found
     5  // in the 3rd-Party License/fasthttprouter file.
     6  
     7  package gramework
     8  
     9  import (
    10  	"bufio"
    11  	"bytes"
    12  	"fmt"
    13  	"net"
    14  	"net/http"
    15  	"os"
    16  	"runtime/debug"
    17  	"strings"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/valyala/fasthttp"
    22  )
    23  
    24  type (
    25  	// handlerStruct struct {
    26  	// 	handeled *bool
    27  	// }
    28  
    29  	// mockFileSystem struct {
    30  	// 	opened bool
    31  	// }
    32  
    33  	readWriter struct {
    34  		net.Conn
    35  		r bytes.Buffer
    36  		w bytes.Buffer
    37  	}
    38  )
    39  
    40  var zeroTCPAddr = &net.TCPAddr{
    41  	IP: net.IPv4zero,
    42  }
    43  
    44  func TestRouter(t *testing.T) {
    45  	router := New()
    46  
    47  	routed := false
    48  	router.Handle("GET", "/user/:name", func(ctx *Context) {
    49  		routed = true
    50  		want := map[string]string{"name": "gopher"}
    51  
    52  		if ctx.UserValue("name") != want["name"] {
    53  			t.Fatalf("wrong wildcard values: want %v, got %v", want["name"], ctx.UserValue("name"))
    54  		}
    55  		ctx.Success("foo/bar", []byte("success"))
    56  	})
    57  
    58  	s := &fasthttp.Server{
    59  		Handler: router.handler(),
    60  	}
    61  
    62  	rw := new(readWriter)
    63  	rw.r.WriteString("GET /user/gopher?baz HTTP/1.1\r\n\r\n")
    64  
    65  	ch := make(chan error)
    66  	go func() {
    67  		ch <- s.ServeConn(rw)
    68  	}()
    69  
    70  	select {
    71  	case err := <-ch:
    72  		if err != nil {
    73  			t.Fatalf("return error %s", err)
    74  		}
    75  	case <-time.After(100 * time.Millisecond):
    76  		t.Fatalf("timeout")
    77  	}
    78  
    79  	if !routed {
    80  		t.Fatal("routing failed")
    81  	}
    82  }
    83  
    84  // func (h handlerStruct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    85  // 	*h.handeled = true
    86  // }
    87  
    88  func TestRouterAPI(t *testing.T) {
    89  	var get, head, options, post, put, patch, deleted bool
    90  
    91  	app := New()
    92  	app.GET("/GET", func(ctx *Context) {
    93  		get = true
    94  	})
    95  	app.HEAD("/GET", func(ctx *Context) {
    96  		head = true
    97  	})
    98  	app.OPTIONS("/GET", func(ctx *Context) {
    99  		options = true
   100  	})
   101  	app.POST("/POST", func(ctx *Context) {
   102  		post = true
   103  	})
   104  	app.PUT("/PUT", func(ctx *Context) {
   105  		put = true
   106  	})
   107  	app.PATCH("/PATCH", func(ctx *Context) {
   108  		patch = true
   109  	})
   110  	app.DELETE("/DELETE", func(ctx *Context) {
   111  		deleted = true
   112  	})
   113  
   114  	s := &fasthttp.Server{
   115  		Handler: app.handler(),
   116  	}
   117  
   118  	rw := new(readWriter)
   119  	ch := make(chan error)
   120  
   121  	rw.r.WriteString("GET /GET HTTP/1.1\r\n\r\n")
   122  	go func() {
   123  		ch <- s.ServeConn(rw)
   124  	}()
   125  	select {
   126  	case err := <-ch:
   127  		if err != nil {
   128  			t.Fatalf("return error %s", err)
   129  		}
   130  	case <-time.After(100 * time.Millisecond):
   131  		t.Fatalf("timeout")
   132  	}
   133  	if !get {
   134  		t.Error("routing GET failed")
   135  	}
   136  
   137  	rw.r.WriteString("HEAD /GET HTTP/1.1\r\n\r\n")
   138  	go func() {
   139  		ch <- s.ServeConn(rw)
   140  	}()
   141  	select {
   142  	case err := <-ch:
   143  		if err != nil {
   144  			t.Fatalf("return error %s", err)
   145  		}
   146  	case <-time.After(100 * time.Millisecond):
   147  		t.Fatalf("timeout")
   148  	}
   149  	if !head {
   150  		t.Error("routing HEAD failed")
   151  	}
   152  
   153  	rw.r.WriteString("OPTIONS /GET HTTP/1.1\r\n\r\n")
   154  	go func() {
   155  		ch <- s.ServeConn(rw)
   156  	}()
   157  	select {
   158  	case err := <-ch:
   159  		if err != nil {
   160  			t.Fatalf("return error %s", err)
   161  		}
   162  	case <-time.After(100 * time.Millisecond):
   163  		t.Fatalf("timeout")
   164  	}
   165  	if !options {
   166  		t.Error("routing OPTIONS failed")
   167  	}
   168  
   169  	rw.r.WriteString("POST /POST HTTP/1.1\r\n\r\n")
   170  	go func() {
   171  		ch <- s.ServeConn(rw)
   172  	}()
   173  	select {
   174  	case err := <-ch:
   175  		if err != nil {
   176  			t.Fatalf("return error %s", err)
   177  		}
   178  	case <-time.After(100 * time.Millisecond):
   179  		t.Fatalf("timeout")
   180  	}
   181  	if !post {
   182  		t.Error("routing POST failed")
   183  	}
   184  
   185  	rw.r.WriteString("PUT /PUT HTTP/1.1\r\n\r\n")
   186  	go func() {
   187  		ch <- s.ServeConn(rw)
   188  	}()
   189  	select {
   190  	case err := <-ch:
   191  		if err != nil {
   192  			t.Fatalf("return error %s", err)
   193  		}
   194  	case <-time.After(100 * time.Millisecond):
   195  		t.Fatalf("timeout")
   196  	}
   197  	if !put {
   198  		t.Error("routing PUT failed")
   199  	}
   200  
   201  	rw.r.WriteString("PATCH /PATCH HTTP/1.1\r\n\r\n")
   202  	go func() {
   203  		ch <- s.ServeConn(rw)
   204  	}()
   205  	select {
   206  	case err := <-ch:
   207  		if err != nil {
   208  			t.Fatalf("return error %s", err)
   209  		}
   210  	case <-time.After(100 * time.Millisecond):
   211  		t.Fatalf("timeout")
   212  	}
   213  	if !patch {
   214  		t.Error("routing PATCH failed")
   215  	}
   216  
   217  	rw.r.WriteString("DELETE /DELETE HTTP/1.1\r\n\r\n")
   218  	go func() {
   219  		ch <- s.ServeConn(rw)
   220  	}()
   221  	select {
   222  	case err := <-ch:
   223  		if err != nil {
   224  			t.Fatalf("return error %s", err)
   225  		}
   226  	case <-time.After(100 * time.Millisecond):
   227  		t.Fatalf("timeout")
   228  	}
   229  	if !deleted {
   230  		t.Error("routing DELETE failed")
   231  	}
   232  }
   233  
   234  func TestRouterWildAnyCache(t *testing.T) {
   235  	var get bool
   236  
   237  	app := New()
   238  	app.GET("/*any", func(ctx *Context) {
   239  		get = true
   240  	})
   241  	s := &fasthttp.Server{
   242  		Handler: app.handler(),
   243  	}
   244  
   245  	rw := new(readWriter)
   246  	ch := make(chan error)
   247  
   248  	boilCache := 64 // It works on values greater than the cache threshold (32).
   249  	for i := 0; i < boilCache; i++ {
   250  		app.defaultRouter.Allowed("/GET", "OPTIONS")
   251  	}
   252  
   253  	rw.r.WriteString("GET /GET HTTP/1.1\r\n\r\n")
   254  	go func() {
   255  		ch <- s.ServeConn(rw)
   256  	}()
   257  	select {
   258  	case err := <-ch:
   259  		if err != nil {
   260  			t.Fatalf("return error %s", err)
   261  		}
   262  	case <-time.After(100 * time.Millisecond):
   263  		t.Fatalf("timeout")
   264  	}
   265  	if !get {
   266  		t.Error("routing GET failed")
   267  	}
   268  }
   269  
   270  func TestRouterWildAnyWithArgsCache(t *testing.T) {
   271  	var get bool
   272  	var getArgs map[string][]string
   273  	var green bool
   274  	var greenValue string
   275  
   276  	app := New()
   277  	app.GET("/GET/*any", func(ctx *Context) {
   278  		get = true
   279  		getArgs = ctx.GETParams()
   280  	})
   281  	app.GET("/GREEN/:CORN", func(ctx *Context) {
   282  		green = true
   283  		greenValue = ctx.UserValue("CORN").(string)
   284  	})
   285  
   286  	s := &fasthttp.Server{
   287  		Handler: app.handler(),
   288  	}
   289  
   290  	rw := new(readWriter)
   291  	ch := make(chan error)
   292  
   293  	boilCache := 64 // It works on values greater than the cache threshold (32).
   294  	for i := 0; i < boilCache; i++ {
   295  		app.defaultRouter.Allowed("/GET/ANY?foo=bar&fizz=buzz&fish", "OPTIONS")
   296  		app.defaultRouter.Allowed("/GET/ANY", "OPTIONS")
   297  		app.defaultRouter.Allowed("/GET", "OPTIONS")
   298  		app.defaultRouter.Allowed("/GREEN/CORN", "OPTIONS")
   299  		app.defaultRouter.Allowed("/GREEN", "OPTIONS")
   300  	}
   301  
   302  	rw.r.WriteString("GET /GET/ANY?foo=bar&fizz=buzz&fish HTTP/1.1\r\n\r\n")
   303  	go func() {
   304  		ch <- s.ServeConn(rw)
   305  	}()
   306  	select {
   307  	case err := <-ch:
   308  		if err != nil {
   309  			t.Fatalf("return error %s", err)
   310  		}
   311  	case <-time.After(100 * time.Millisecond):
   312  		t.Fatalf("timeout")
   313  	}
   314  	if !get {
   315  		t.Error("routing GET failed")
   316  	}
   317  	if getArgs == nil {
   318  		t.Error("get args should not be empty")
   319  	}
   320  	if foo, ok := getArgs["foo"]; ok {
   321  		if len(foo) != 1 || foo[0] != "bar" {
   322  			t.Error("the foo arg lost its bar value")
   323  		}
   324  	} else {
   325  		t.Error("the foo arg must exist")
   326  	}
   327  	if fizz, ok := getArgs["fizz"]; ok {
   328  		if len(fizz) != 1 || fizz[0] != "buzz" {
   329  			t.Error("the fizz arg lost its buzz value")
   330  		}
   331  	} else {
   332  		t.Error("the fizz arg must exist")
   333  	}
   334  	if fish, ok := getArgs["fish"]; ok {
   335  		if len(fish) > 0 && len(strings.Join(fish, "")) > 0 {
   336  			t.Error("how much is the fish?", fish)
   337  		}
   338  	} else {
   339  		t.Error("the fish arg must exist")
   340  	}
   341  
   342  	rw.r.WriteString("GET /GREEN/CORN HTTP/1.1\r\n\r\n")
   343  	go func() {
   344  		ch <- s.ServeConn(rw)
   345  	}()
   346  	select {
   347  	case err := <-ch:
   348  		if err != nil {
   349  			t.Fatalf("return error %s", err)
   350  		}
   351  	case <-time.After(100 * time.Millisecond):
   352  		t.Fatalf("timeout")
   353  	}
   354  	if !green {
   355  		t.Error("routing GREEN failed")
   356  	}
   357  	if len(greenValue) == 0 {
   358  		t.Error("the green value must exist")
   359  	}
   360  	if greenValue != "CORN" {
   361  		t.Errorf("the green value must be equal to 'CORN', but have '%s'", greenValue)
   362  	}
   363  }
   364  
   365  func TestRouterRoot(t *testing.T) {
   366  	router := New()
   367  	recv := catchPanic(func() {
   368  		router.GET("noSlashRoot", nil)
   369  	})
   370  	if recv == nil {
   371  		t.Fatal("registering path not beginning with '/' did not panic")
   372  	}
   373  }
   374  
   375  // func TestRouterOPTIONS(t *testing.T) {
   376  // 	// TODO: because fasthttp is not support OPTIONS method now,
   377  // 	// these test cases will be used in the future.
   378  // 	handlerFunc := func(_ *fasthttp.RequestCtx) {}
   379  
   380  // 	router := New()
   381  // 	router.POST("/path", handlerFunc)
   382  
   383  // 	// test not allowed
   384  // 	// * (server)
   385  // 	s := &fasthttp.Server{
   386  // 		Handler: router.handler(),
   387  // 	}
   388  
   389  // 	rw := new(readWriter{})
   390  // 	ch := make(chan error)
   391  
   392  // 	rw.r.WriteString("OPTIONS * HTTP/1.1\r\nHost:\r\n\r\n")
   393  // 	go func() {
   394  // 		ch <- s.ServeConn(rw)
   395  // 	}()
   396  // 	select {
   397  // 	case err := <-ch:
   398  // 		if err != nil {
   399  // 			t.Fatalf("return error %s", err)
   400  // 		}
   401  // 	case <-time.After(100 * time.Millisecond):
   402  // 		t.Fatalf("timeout")
   403  // 	}
   404  // 	br := bufio.NewReader(&rw.w)
   405  // 	var resp fasthttp.Response
   406  // 	if err := resp.Read(br); err != nil {
   407  // 		t.Fatalf("Unexpected error when reading response: %s", err)
   408  // 	}
   409  // 	if resp.Header.StatusCode() != fasthttp.StatusOK {
   410  // 		t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
   411  // 			resp.Header.StatusCode(), resp.Header.String())
   412  // 	} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, OPTIONS" {
   413  // 		t.Error("unexpected Allow header value: " + allow)
   414  // 	}
   415  
   416  // 	// path
   417  // 	rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n")
   418  // 	go func() {
   419  // 		ch <- s.ServeConn(rw)
   420  // 	}()
   421  // 	select {
   422  // 	case err := <-ch:
   423  // 		if err != nil {
   424  // 			t.Fatalf("return error %s", err)
   425  // 		}
   426  // 	case <-time.After(100 * time.Millisecond):
   427  // 		t.Fatalf("timeout")
   428  // 	}
   429  // 	if err := resp.Read(br); err != nil {
   430  // 		t.Fatalf("Unexpected error when reading response: %s", err)
   431  // 	}
   432  // 	if resp.Header.StatusCode() != fasthttp.StatusOK {
   433  // 		t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
   434  // 			resp.Header.StatusCode(), resp.Header.String())
   435  // 	} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, OPTIONS" {
   436  // 		t.Error("unexpected Allow header value: " + allow)
   437  // 	}
   438  
   439  // 	rw.r.WriteString("OPTIONS /doesnotexist HTTP/1.1\r\n\r\n")
   440  // 	go func() {
   441  // 		ch <- s.ServeConn(rw)
   442  // 	}()
   443  // 	select {
   444  // 	case err := <-ch:
   445  // 		if err != nil {
   446  // 			t.Fatalf("return error %s", err)
   447  // 		}
   448  // 	case <-time.After(100 * time.Millisecond):
   449  // 		t.Fatalf("timeout")
   450  // 	}
   451  // 	if err := resp.Read(br); err != nil {
   452  // 		t.Fatalf("Unexpected error when reading response: %s", err)
   453  // 	}
   454  // 	if !(resp.Header.StatusCode() == fasthttp.StatusNotFound) {
   455  // 		t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
   456  // 			resp.Header.StatusCode(), resp.Header.String())
   457  // 	}
   458  
   459  // 	// add another method
   460  // 	router.GET("/path", handlerFunc)
   461  
   462  // 	// test again
   463  // 	// * (server)
   464  // 	rw.r.WriteString("OPTIONS * HTTP/1.1\r\n\r\n")
   465  // 	go func() {
   466  // 		ch <- s.ServeConn(rw)
   467  // 	}()
   468  // 	select {
   469  // 	case err := <-ch:
   470  // 		if err != nil {
   471  // 			t.Fatalf("return error %s", err)
   472  // 		}
   473  // 	case <-time.After(100 * time.Millisecond):
   474  // 		t.Fatalf("timeout")
   475  // 	}
   476  // 	if err := resp.Read(br); err != nil {
   477  // 		t.Fatalf("Unexpected error when reading response: %s", err)
   478  // 	}
   479  // 	if resp.Header.StatusCode() != fasthttp.StatusOK {
   480  // 		t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
   481  // 			resp.Header.StatusCode(), resp.Header.String())
   482  // 	} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET, OPTIONS" && allow != "GET, POST, OPTIONS" {
   483  // 		t.Error("unexpected Allow header value: " + allow)
   484  // 	}
   485  
   486  // 	// path
   487  // 	rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n")
   488  // 	go func() {
   489  // 		ch <- s.ServeConn(rw)
   490  // 	}()
   491  // 	select {
   492  // 	case err := <-ch:
   493  // 		if err != nil {
   494  // 			t.Fatalf("return error %s", err)
   495  // 		}
   496  // 	case <-time.After(100 * time.Millisecond):
   497  // 		t.Fatalf("timeout")
   498  // 	}
   499  // 	if err := resp.Read(br); err != nil {
   500  // 		t.Fatalf("Unexpected error when reading response: %s", err)
   501  // 	}
   502  // 	if resp.Header.StatusCode() != fasthttp.StatusOK {
   503  // 		t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
   504  // 			resp.Header.StatusCode(), resp.Header.String())
   505  // 	} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET, OPTIONS" && allow != "GET, POST, OPTIONS" {
   506  // 		t.Error("unexpected Allow header value: " + allow)
   507  // 	}
   508  
   509  // 	// custom handler
   510  // 	var custom bool
   511  // 	router.OPTIONS("/path", func(_ *fasthttp.RequestCtx) {
   512  // 		custom = true
   513  // 	})
   514  
   515  // 	// test again
   516  // 	// * (server)
   517  // 	rw.r.WriteString("OPTIONS * HTTP/1.1\r\n\r\n")
   518  // 	go func() {
   519  // 		ch <- s.ServeConn(rw)
   520  // 	}()
   521  // 	select {
   522  // 	case err := <-ch:
   523  // 		if err != nil {
   524  // 			t.Fatalf("return error %s", err)
   525  // 		}
   526  // 	case <-time.After(100 * time.Millisecond):
   527  // 		t.Fatalf("timeout")
   528  // 	}
   529  // 	if err := resp.Read(br); err != nil {
   530  // 		t.Fatalf("Unexpected error when reading response: %s", err)
   531  // 	}
   532  // 	if resp.Header.StatusCode() != fasthttp.StatusOK {
   533  // 		t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
   534  // 			resp.Header.StatusCode(), resp.Header.String())
   535  // 	} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET, OPTIONS" && allow != "GET, POST, OPTIONS" {
   536  // 		t.Error("unexpected Allow header value: " + allow)
   537  // 	}
   538  // 	if custom {
   539  // 		t.Error("custom handler called on *")
   540  // 	}
   541  
   542  // 	// path
   543  // 	rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n")
   544  // 	go func() {
   545  // 		ch <- s.ServeConn(rw)
   546  // 	}()
   547  // 	select {
   548  // 	case err := <-ch:
   549  // 		if err != nil {
   550  // 			t.Fatalf("return error %s", err)
   551  // 		}
   552  // 	case <-time.After(100 * time.Millisecond):
   553  // 		t.Fatalf("timeout")
   554  // 	}
   555  // 	if err := resp.Read(br); err != nil {
   556  // 		t.Fatalf("Unexpected error when reading response: %s", err)
   557  // 	}
   558  // 	if resp.Header.StatusCode() != fasthttp.StatusOK {
   559  // 		t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
   560  // 			resp.Header.StatusCode(), resp.Header.String())
   561  // 	}
   562  // 	if !custom {
   563  // 		t.Error("custom handler not called")
   564  // 	}
   565  // }
   566  
   567  func TestRouterNotAllowed(t *testing.T) {
   568  	handlerFunc := func(_ *fasthttp.RequestCtx) {}
   569  
   570  	router := New()
   571  	router.POST("/path", handlerFunc)
   572  
   573  	// Test not allowed
   574  	s := &fasthttp.Server{
   575  		Handler: router.handler(),
   576  	}
   577  
   578  	rw := new(readWriter)
   579  	ch := make(chan error)
   580  
   581  	rw.r.WriteString("GET /path HTTP/1.1\r\n\r\n")
   582  	go func() {
   583  		ch <- s.ServeConn(rw)
   584  	}()
   585  	select {
   586  	case err := <-ch:
   587  		if err != nil {
   588  			t.Fatalf("return error %s", err)
   589  		}
   590  	case <-time.After(100 * time.Millisecond):
   591  		t.Fatalf("timeout")
   592  	}
   593  	br := bufio.NewReader(&rw.w)
   594  	var resp fasthttp.Response
   595  	if err := resp.Read(br); err != nil {
   596  		t.Fatalf("Unexpected error when reading response: %s", err)
   597  	}
   598  	if !(resp.Header.StatusCode() == fasthttp.StatusMethodNotAllowed) {
   599  		t.Errorf("NotAllowed handling failed: Code=%d. Actual=%d", resp.Header.StatusCode(), fasthttp.StatusMethodNotAllowed)
   600  	} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, OPTIONS" {
   601  		t.Error("unexpected Allow header value: " + allow)
   602  	}
   603  
   604  	// add another method
   605  	router.DELETE("/path", handlerFunc)
   606  	router.OPTIONS("/path", handlerFunc) // must be ignored
   607  
   608  	// test again
   609  	rw.r.WriteString("GET /path HTTP/1.1\r\n\r\n")
   610  	go func() {
   611  		ch <- s.ServeConn(rw)
   612  	}()
   613  	select {
   614  	case err := <-ch:
   615  		if err != nil {
   616  			t.Fatalf("return error %s", err)
   617  		}
   618  	case <-time.After(100 * time.Millisecond):
   619  		t.Fatalf("timeout")
   620  	}
   621  	if err := resp.Read(br); err != nil {
   622  		t.Fatalf("Unexpected error when reading response: %s", err)
   623  	}
   624  	if !(resp.Header.StatusCode() == fasthttp.StatusMethodNotAllowed) {
   625  		t.Errorf("NotAllowed handling failed: Code=%d. Actual=%d", resp.Header.StatusCode(), fasthttp.StatusMethodNotAllowed)
   626  	} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, DELETE, OPTIONS" && allow != "DELETE, POST, OPTIONS" {
   627  		t.Error("unexpected Allow header value: " + allow)
   628  	}
   629  
   630  	responseText := "custom method"
   631  	router.MethodNotAllowed(func(ctx *Context) {
   632  		ctx.SetStatusCode(fasthttp.StatusTeapot)
   633  		_, e := ctx.Write([]byte(responseText))
   634  		_ = e
   635  	})
   636  	rw.r.WriteString("GET /path HTTP/1.1\r\n\r\n")
   637  	go func() {
   638  		ch <- s.ServeConn(rw)
   639  	}()
   640  	select {
   641  	case err := <-ch:
   642  		if err != nil {
   643  			t.Fatalf("return error %s", err)
   644  		}
   645  	case <-time.After(100 * time.Millisecond):
   646  		t.Fatalf("timeout")
   647  	}
   648  	if err := resp.Read(br); err != nil {
   649  		t.Fatalf("Unexpected error when reading response: %s", err)
   650  	}
   651  	if !bytes.Equal(resp.Body(), []byte(responseText)) {
   652  		t.Errorf("unexpected response got %q want %q", string(resp.Body()), responseText)
   653  	}
   654  	if resp.Header.StatusCode() != fasthttp.StatusTeapot {
   655  		t.Errorf("unexpected response code %d want %d", resp.Header.StatusCode(), fasthttp.StatusTeapot)
   656  	}
   657  	if allow := string(resp.Header.Peek("Allow")); allow != "POST, DELETE, OPTIONS" && allow != "DELETE, POST, OPTIONS" {
   658  		t.Error("unexpected Allow header value: " + allow)
   659  	}
   660  }
   661  
   662  func TestRouterNotFound(t *testing.T) {
   663  	handlerFunc := func(_ *fasthttp.RequestCtx) {}
   664  
   665  	router := New()
   666  	router.GET("/path", handlerFunc)
   667  	router.GET("/dir/", handlerFunc)
   668  	router.GET("/", handlerFunc)
   669  	router.GET("/path/:user", handlerFunc)
   670  	router.Sub("/abc").GET("/:user", handlerFunc)
   671  
   672  	testRoutes := []struct {
   673  		route    string
   674  		code     int
   675  		location string
   676  	}{
   677  		{"/path/", 301, "/path"},                       // TSR -/
   678  		{"/dir", 200, ""},                              // TSR -/
   679  		{"/", 200, ""},                                 // TSR +/
   680  		{"/PATH", 301, "/path"},                        // Fixed Case
   681  		{"/DIR", 301, "/dir"},                          // Fixed Case
   682  		{"/PATH/", 301, "/path"},                       // Fixed Case -/
   683  		{"/DIR/", 301, "/dir"},                         // Fixed Case +/
   684  		{"/paTh/?name=foo", 301, "/path?name=foo"},     // Fixed Case With Params +/
   685  		{"/paTh?name=foo", 301, "/path?name=foo"},      // Fixed Case With Params +/
   686  		{"/../path", 200, ""},                          // CleanPath
   687  		{"/nope", 404, ""},                             // NotFound
   688  		{"/path/?name=foo", 301, "/path?name=foo"},     // TSR Case With Params
   689  		{"/path/u/?name=foo", 301, "/path/u?name=foo"}, // Dynamic TSR -/
   690  		{"/abc/u/?name=foo", 301, "/abc/u?name=foo"},   // Sub Dynamic TSR -/
   691  		{"/AbC/u/?name=foo", 301, "/abc/u?name=foo"},   // Sub Dynamic Fixed Case -/
   692  	}
   693  
   694  	s := &fasthttp.Server{
   695  		Handler: router.handler(),
   696  	}
   697  
   698  	rw := new(readWriter)
   699  	br := bufio.NewReader(&rw.w)
   700  	var resp fasthttp.Response
   701  	ch := make(chan error)
   702  	for _, tr := range testRoutes {
   703  		t.Logf("testing %v, want %v code", tr.route, tr.code)
   704  		rw.r.WriteString(fmt.Sprintf("GET %s HTTP/1.1\r\n\r\n", tr.route))
   705  		go func() {
   706  			ch <- s.ServeConn(rw)
   707  		}()
   708  		select {
   709  		case err := <-ch:
   710  			if err != nil {
   711  				t.Fatalf("return error %s", err)
   712  			}
   713  		case <-time.After(100 * time.Millisecond):
   714  			t.Fatalf("timeout")
   715  		}
   716  		if err := resp.Read(br); err != nil {
   717  			t.Fatalf("Unexpected error when reading response: %s", err)
   718  		}
   719  		if !(resp.Header.StatusCode() == tr.code) {
   720  			t.Errorf("NotFound handling route %s failed: Code=%d want=%d",
   721  				tr.route, resp.Header.StatusCode(), tr.code)
   722  		}
   723  		respLocation := string(resp.Header.Peek("Location"))
   724  		if tr.code == 301 && respLocation != tr.location {
   725  			t.Errorf("Wrong location header %s failed: Location=%s want=%s",
   726  				tr.route, respLocation, tr.location)
   727  		}
   728  	}
   729  	t.Log("not found test")
   730  	// Test custom not found handler
   731  	var notFound bool
   732  	router.NotFound(func(ctx *Context) {
   733  		ctx.SetStatusCode(404)
   734  		notFound = true
   735  	})
   736  	rw.r.WriteString("GET /nope HTTP/1.1\r\n\r\n")
   737  	go func() {
   738  		ch <- s.ServeConn(rw)
   739  	}()
   740  	select {
   741  	case err := <-ch:
   742  		if err != nil {
   743  			t.Fatalf("return error %s", err)
   744  		}
   745  	case <-time.After(100 * time.Millisecond):
   746  		t.Fatalf("timeout")
   747  	}
   748  	if err := resp.Read(br); err != nil {
   749  		t.Fatalf("Unexpected error when reading response: %s", err)
   750  	}
   751  	if !(resp.Header.StatusCode() == http.StatusNotFound && notFound) {
   752  		t.Errorf(
   753  			"Custom NotFound handler failed: Code=%d, Header=%v, url=/nope",
   754  			resp.Header.StatusCode(),
   755  			string(resp.Header.Peek("Location")),
   756  		)
   757  	}
   758  
   759  	// Test other method than GET (want 307 instead of 301)
   760  	router.PATCH("/path", handlerFunc)
   761  	rw.r.WriteString("PATCH /path/ HTTP/1.1\r\n\r\n")
   762  	go func() {
   763  		ch <- s.ServeConn(rw)
   764  	}()
   765  	select {
   766  	case err := <-ch:
   767  		if err != nil {
   768  			t.Fatalf("return error %s", err)
   769  		}
   770  	case <-time.After(100 * time.Millisecond):
   771  		t.Fatalf("timeout")
   772  	}
   773  	if err := resp.Read(br); err != nil {
   774  		t.Fatalf("Unexpected error when reading response: %s", err)
   775  	}
   776  	if resp.Header.StatusCode() != 307 {
   777  		t.Errorf("Custom NotFound handler failed: Code=%d, Header=%v, url=/path",
   778  			resp.Header.StatusCode(),
   779  			string(resp.Header.Peek("Location")),
   780  		)
   781  	}
   782  
   783  	// Test special case where no node for the prefix "/" exists
   784  	router = New()
   785  	router.GET("/a", handlerFunc)
   786  	s.Handler = router.handler()
   787  	rw.r.WriteString("GET / HTTP/1.1\r\n\r\n")
   788  	go func() {
   789  		ch <- s.ServeConn(rw)
   790  	}()
   791  	select {
   792  	case err := <-ch:
   793  		if err != nil {
   794  			t.Fatalf("return error %s", err)
   795  		}
   796  	case <-time.After(100 * time.Millisecond):
   797  		t.Fatalf("timeout")
   798  	}
   799  	if err := resp.Read(br); err != nil {
   800  		t.Fatalf("Unexpected error when reading response: %s", err)
   801  	}
   802  	if !(resp.Header.StatusCode() == 404) {
   803  		t.Errorf("NotFound handling route / failed: Code=%d, Header=%v, url=/",
   804  			resp.Header.StatusCode(),
   805  			string(resp.Header.Peek("Location")),
   806  		)
   807  	}
   808  }
   809  
   810  func TestRouterPanicHandler(t *testing.T) {
   811  	router := New()
   812  	panicHandled := false
   813  
   814  	router.PanicHandler(func(ctx *Context, p interface{}) {
   815  		panicHandled = true
   816  	})
   817  
   818  	router.Handle("PUT", "/user/:name", func(_ *fasthttp.RequestCtx) {
   819  		panic("oops!")
   820  	})
   821  
   822  	defer func() {
   823  		if rcv := recover(); rcv != nil {
   824  			t.Fatal("handling panic failed")
   825  		}
   826  	}()
   827  
   828  	s := &fasthttp.Server{
   829  		Handler: router.handler(),
   830  	}
   831  
   832  	rw := new(readWriter)
   833  	ch := make(chan error)
   834  
   835  	rw.r.WriteString(string("PUT /user/gopher HTTP/1.1\r\n\r\n"))
   836  	go func() {
   837  		ch <- s.ServeConn(rw)
   838  	}()
   839  	select {
   840  	case err := <-ch:
   841  		if err != nil {
   842  			t.Fatalf("return error %s", err)
   843  		}
   844  	case <-time.After(100 * time.Millisecond):
   845  		t.Fatalf("timeout")
   846  	}
   847  
   848  	if !panicHandled {
   849  		t.Fatal("simulating failed")
   850  	}
   851  }
   852  
   853  func TestRouterLookup(t *testing.T) {
   854  
   855  	defer func() {
   856  		if r := recover(); r != nil {
   857  			Logger.Errorf("panic handled: %v", r)
   858  			debug.PrintStack()
   859  		}
   860  	}()
   861  	routed := false
   862  	wantHandle := func(_ *fasthttp.RequestCtx) {
   863  		routed = true
   864  	}
   865  
   866  	router := New()
   867  	ctx := &Context{
   868  		RequestCtx: &fasthttp.RequestCtx{},
   869  		Logger:     Logger,
   870  		App:        router,
   871  	}
   872  
   873  	// try empty router first
   874  	handle, tsr := router.defaultRouter.Lookup("GET", "/nope", ctx)
   875  	if handle != nil {
   876  		t.Fatalf("Got handle for unregistered pattern: %v", handle)
   877  	}
   878  	if tsr {
   879  		t.Error("Got wrong TSR recommendation!")
   880  	}
   881  
   882  	// insert route and try again
   883  	router.GET("/user/:name", wantHandle)
   884  
   885  	handle, _ = router.defaultRouter.Lookup("GET", "/user/gopher", ctx)
   886  	if handle == nil {
   887  		t.Fatal("Got no handle!")
   888  	} else {
   889  		handle(nil)
   890  		if !routed {
   891  			t.Fatal("Routing failed!")
   892  		}
   893  	}
   894  	if ctx.UserValue("name") != "gopher" {
   895  		t.Error("Param not set!")
   896  	}
   897  
   898  	handle, tsr = router.defaultRouter.Lookup("GET", "/user/gopher/", ctx)
   899  	if handle != nil {
   900  		t.Fatalf("Got handle for unregistered pattern: %v", handle)
   901  	}
   902  	if !tsr {
   903  		t.Error("Got no TSR recommendation!")
   904  	}
   905  
   906  	handle, tsr = router.defaultRouter.Lookup("GET", "/nope", ctx)
   907  	if handle != nil {
   908  		t.Fatalf("Got handle for unregistered pattern: %v", handle)
   909  	}
   910  	if tsr {
   911  		t.Error("Got wrong TSR recommendation!")
   912  	}
   913  }
   914  
   915  // func (mfs *mockFileSystem) Open(name string) (http.File, error) {
   916  // 	mfs.opened = true
   917  // 	return nil, errors.New("this is just a mock")
   918  // }
   919  
   920  func TestRouterServeFiles(t *testing.T) {
   921  	router := New()
   922  
   923  	recv := catchPanic(func() {
   924  		router.defaultRouter.ServeFiles("/noFilepath", os.TempDir())
   925  	})
   926  	if recv == nil {
   927  		t.Fatal("registering path not ending with '*filepath' did not panic")
   928  	}
   929  	body := []byte("fake ico")
   930  	err := os.WriteFile(os.TempDir()+"/favicon.ico", body, 0644)
   931  	if err != nil {
   932  		t.Fatal(err)
   933  	}
   934  
   935  	router.defaultRouter.ServeFiles("/*filepath", os.TempDir())
   936  
   937  	s := &fasthttp.Server{
   938  		Handler: router.handler(),
   939  	}
   940  
   941  	rw := new(readWriter)
   942  	ch := make(chan error)
   943  
   944  	rw.r.WriteString(string("GET /favicon.ico HTTP/1.1\r\n\r\n"))
   945  	go func() {
   946  		ch <- s.ServeConn(rw)
   947  	}()
   948  	select {
   949  	case err := <-ch:
   950  		if err != nil {
   951  			t.Fatalf("return error %s", err)
   952  		}
   953  	case <-time.After(500 * time.Millisecond):
   954  		t.Fatalf("timeout")
   955  	}
   956  
   957  	br := bufio.NewReader(&rw.w)
   958  	var resp fasthttp.Response
   959  	if err := resp.Read(br); err != nil {
   960  		t.Fatalf("Unexpected error when reading response: %s", err)
   961  	}
   962  	if resp.Header.StatusCode() != 200 {
   963  		t.Fatalf("Unexpected status code %d. Expected %d", resp.Header.StatusCode(), 423)
   964  	}
   965  	if !bytes.Equal(resp.Body(), body) {
   966  		t.Fatalf("Unexpected body %q. Expected %q", resp.Body(), string(body))
   967  	}
   968  }
   969  
   970  func (rw *readWriter) Close() error {
   971  	return nil
   972  }
   973  
   974  func (rw *readWriter) Read(b []byte) (int, error) {
   975  	return rw.r.Read(b)
   976  }
   977  
   978  func (rw *readWriter) Write(b []byte) (int, error) {
   979  	return rw.w.Write(b)
   980  }
   981  
   982  func (rw *readWriter) RemoteAddr() net.Addr {
   983  	return zeroTCPAddr
   984  }
   985  
   986  func (rw *readWriter) LocalAddr() net.Addr {
   987  	return zeroTCPAddr
   988  }
   989  
   990  func (rw *readWriter) SetReadDeadline(t time.Time) error {
   991  	return nil
   992  }
   993  
   994  func (rw *readWriter) SetWriteDeadline(t time.Time) error {
   995  	return nil
   996  }