github.com/gofiber/fiber/v2@v2.47.0/helpers_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  package fiber
     6  
     7  import (
     8  	"fmt"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/gofiber/fiber/v2/utils"
    14  
    15  	"github.com/valyala/fasthttp"
    16  )
    17  
    18  // go test -v -run=Test_Utils_ -count=3
    19  func Test_Utils_ETag(t *testing.T) {
    20  	t.Parallel()
    21  	app := New()
    22  	t.Run("Not Status OK", func(t *testing.T) {
    23  		t.Parallel()
    24  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
    25  		defer app.ReleaseCtx(c)
    26  		err := c.SendString("Hello, World!")
    27  		utils.AssertEqual(t, nil, err)
    28  		c.Status(201)
    29  		setETag(c, false)
    30  		utils.AssertEqual(t, "", string(c.Response().Header.Peek(HeaderETag)))
    31  	})
    32  
    33  	t.Run("No Body", func(t *testing.T) {
    34  		t.Parallel()
    35  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
    36  		defer app.ReleaseCtx(c)
    37  		setETag(c, false)
    38  		utils.AssertEqual(t, "", string(c.Response().Header.Peek(HeaderETag)))
    39  	})
    40  
    41  	t.Run("Has HeaderIfNoneMatch", func(t *testing.T) {
    42  		t.Parallel()
    43  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
    44  		defer app.ReleaseCtx(c)
    45  		err := c.SendString("Hello, World!")
    46  		utils.AssertEqual(t, nil, err)
    47  		c.Request().Header.Set(HeaderIfNoneMatch, `"13-1831710635"`)
    48  		setETag(c, false)
    49  		utils.AssertEqual(t, 304, c.Response().StatusCode())
    50  		utils.AssertEqual(t, "", string(c.Response().Header.Peek(HeaderETag)))
    51  		utils.AssertEqual(t, "", string(c.Response().Body()))
    52  	})
    53  
    54  	t.Run("No HeaderIfNoneMatch", func(t *testing.T) {
    55  		t.Parallel()
    56  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
    57  		defer app.ReleaseCtx(c)
    58  		err := c.SendString("Hello, World!")
    59  		utils.AssertEqual(t, nil, err)
    60  		setETag(c, false)
    61  		utils.AssertEqual(t, `"13-1831710635"`, string(c.Response().Header.Peek(HeaderETag)))
    62  	})
    63  }
    64  
    65  func Test_Utils_GetOffer(t *testing.T) {
    66  	t.Parallel()
    67  	utils.AssertEqual(t, "", getOffer("hello", acceptsOffer))
    68  	utils.AssertEqual(t, "1", getOffer("", acceptsOffer, "1"))
    69  	utils.AssertEqual(t, "", getOffer("2", acceptsOffer, "1"))
    70  
    71  	utils.AssertEqual(t, "", getOffer("", acceptsOfferType))
    72  	utils.AssertEqual(t, "", getOffer("text/html", acceptsOfferType))
    73  	utils.AssertEqual(t, "", getOffer("text/html", acceptsOfferType, "application/json"))
    74  	utils.AssertEqual(t, "", getOffer("text/html;q=0", acceptsOfferType, "text/html"))
    75  	utils.AssertEqual(t, "", getOffer("application/json, */*; q=0", acceptsOfferType, "image/png"))
    76  	utils.AssertEqual(t, "application/xml", getOffer("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", acceptsOfferType, "application/xml", "application/json"))
    77  	utils.AssertEqual(t, "text/html", getOffer("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", acceptsOfferType, "text/html"))
    78  	utils.AssertEqual(t, "application/pdf", getOffer("text/plain;q=0,application/pdf;q=0.9,*/*;q=0.000", acceptsOfferType, "application/pdf", "application/json"))
    79  	utils.AssertEqual(t, "application/pdf", getOffer("text/plain;q=0,application/pdf;q=0.9,*/*;q=0.000", acceptsOfferType, "application/pdf", "application/json"))
    80  
    81  	utils.AssertEqual(t, "", getOffer("utf-8, iso-8859-1;q=0.5", acceptsOffer))
    82  	utils.AssertEqual(t, "", getOffer("utf-8, iso-8859-1;q=0.5", acceptsOffer, "ascii"))
    83  	utils.AssertEqual(t, "utf-8", getOffer("utf-8, iso-8859-1;q=0.5", acceptsOffer, "utf-8"))
    84  	utils.AssertEqual(t, "iso-8859-1", getOffer("utf-8;q=0, iso-8859-1;q=0.5", acceptsOffer, "utf-8", "iso-8859-1"))
    85  
    86  	utils.AssertEqual(t, "deflate", getOffer("gzip, deflate", acceptsOffer, "deflate"))
    87  	utils.AssertEqual(t, "", getOffer("gzip, deflate;q=0", acceptsOffer, "deflate"))
    88  }
    89  
    90  func Benchmark_Utils_GetOffer(b *testing.B) {
    91  	headers := []string{
    92  		"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    93  		"application/json",
    94  		"utf-8, iso-8859-1;q=0.5",
    95  		"gzip, deflate",
    96  	}
    97  	offers := [][]string{
    98  		{"text/html", "application/xml", "application/xml+xhtml"},
    99  		{"application/json"},
   100  		{"utf-8"},
   101  		{"deflate"},
   102  	}
   103  	for n := 0; n < b.N; n++ {
   104  		for i, header := range headers {
   105  			getOffer(header, acceptsOfferType, offers[i]...)
   106  		}
   107  	}
   108  }
   109  
   110  func Test_Utils_SortAcceptedTypes(t *testing.T) {
   111  	t.Parallel()
   112  	acceptedTypes := []acceptedType{
   113  		{spec: "text/html", quality: 1, specificity: 3, order: 0},
   114  		{spec: "text/*", quality: 0.5, specificity: 2, order: 1},
   115  		{spec: "*/*", quality: 0.1, specificity: 1, order: 2},
   116  		{spec: "application/json", quality: 0.999, specificity: 3, order: 3},
   117  		{spec: "application/xml", quality: 1, specificity: 3, order: 4},
   118  		{spec: "application/pdf", quality: 1, specificity: 3, order: 5},
   119  		{spec: "image/png", quality: 1, specificity: 3, order: 6},
   120  		{spec: "image/jpeg", quality: 1, specificity: 3, order: 7},
   121  		{spec: "image/*", quality: 1, specificity: 2, order: 8},
   122  		{spec: "image/gif", quality: 1, specificity: 3, order: 9},
   123  		{spec: "text/plain", quality: 1, specificity: 3, order: 10},
   124  	}
   125  	sortAcceptedTypes(&acceptedTypes)
   126  	utils.AssertEqual(t, acceptedTypes, []acceptedType{
   127  		{spec: "text/html", quality: 1, specificity: 3, order: 0},
   128  		{spec: "application/xml", quality: 1, specificity: 3, order: 4},
   129  		{spec: "application/pdf", quality: 1, specificity: 3, order: 5},
   130  		{spec: "image/png", quality: 1, specificity: 3, order: 6},
   131  		{spec: "image/jpeg", quality: 1, specificity: 3, order: 7},
   132  		{spec: "image/gif", quality: 1, specificity: 3, order: 9},
   133  		{spec: "text/plain", quality: 1, specificity: 3, order: 10},
   134  		{spec: "image/*", quality: 1, specificity: 2, order: 8},
   135  		{spec: "application/json", quality: 0.999, specificity: 3, order: 3},
   136  		{spec: "text/*", quality: 0.5, specificity: 2, order: 1},
   137  		{spec: "*/*", quality: 0.1, specificity: 1, order: 2},
   138  	})
   139  }
   140  
   141  // go test -v -run=^$ -bench=Benchmark_Utils_SortAcceptedTypes_Sorted -benchmem -count=4
   142  func Benchmark_Utils_SortAcceptedTypes_Sorted(b *testing.B) {
   143  	acceptedTypes := make([]acceptedType, 3)
   144  	for n := 0; n < b.N; n++ {
   145  		acceptedTypes[0] = acceptedType{spec: "text/html", quality: 1, specificity: 1, order: 0}
   146  		acceptedTypes[1] = acceptedType{spec: "text/*", quality: 0.5, specificity: 1, order: 1}
   147  		acceptedTypes[2] = acceptedType{spec: "*/*", quality: 0.1, specificity: 1, order: 2}
   148  		sortAcceptedTypes(&acceptedTypes)
   149  	}
   150  	utils.AssertEqual(b, "text/html", acceptedTypes[0].spec)
   151  	utils.AssertEqual(b, "text/*", acceptedTypes[1].spec)
   152  	utils.AssertEqual(b, "*/*", acceptedTypes[2].spec)
   153  }
   154  
   155  // go test -v -run=^$ -bench=Benchmark_Utils_SortAcceptedTypes_Unsorted -benchmem -count=4
   156  func Benchmark_Utils_SortAcceptedTypes_Unsorted(b *testing.B) {
   157  	acceptedTypes := make([]acceptedType, 11)
   158  	for n := 0; n < b.N; n++ {
   159  		acceptedTypes[0] = acceptedType{spec: "text/html", quality: 1, specificity: 3, order: 0}
   160  		acceptedTypes[1] = acceptedType{spec: "text/*", quality: 0.5, specificity: 2, order: 1}
   161  		acceptedTypes[2] = acceptedType{spec: "*/*", quality: 0.1, specificity: 1, order: 2}
   162  		acceptedTypes[3] = acceptedType{spec: "application/json", quality: 0.999, specificity: 3, order: 3}
   163  		acceptedTypes[4] = acceptedType{spec: "application/xml", quality: 1, specificity: 3, order: 4}
   164  		acceptedTypes[5] = acceptedType{spec: "application/pdf", quality: 1, specificity: 3, order: 5}
   165  		acceptedTypes[6] = acceptedType{spec: "image/png", quality: 1, specificity: 3, order: 6}
   166  		acceptedTypes[7] = acceptedType{spec: "image/jpeg", quality: 1, specificity: 3, order: 7}
   167  		acceptedTypes[8] = acceptedType{spec: "image/*", quality: 1, specificity: 2, order: 8}
   168  		acceptedTypes[9] = acceptedType{spec: "image/gif", quality: 1, specificity: 3, order: 9}
   169  		acceptedTypes[10] = acceptedType{spec: "text/plain", quality: 1, specificity: 3, order: 10}
   170  		sortAcceptedTypes(&acceptedTypes)
   171  	}
   172  	utils.AssertEqual(b, acceptedTypes, []acceptedType{
   173  		{spec: "text/html", quality: 1, specificity: 3, order: 0},
   174  		{spec: "application/xml", quality: 1, specificity: 3, order: 4},
   175  		{spec: "application/pdf", quality: 1, specificity: 3, order: 5},
   176  		{spec: "image/png", quality: 1, specificity: 3, order: 6},
   177  		{spec: "image/jpeg", quality: 1, specificity: 3, order: 7},
   178  		{spec: "image/gif", quality: 1, specificity: 3, order: 9},
   179  		{spec: "text/plain", quality: 1, specificity: 3, order: 10},
   180  		{spec: "image/*", quality: 1, specificity: 2, order: 8},
   181  		{spec: "application/json", quality: 0.999, specificity: 3, order: 3},
   182  		{spec: "text/*", quality: 0.5, specificity: 2, order: 1},
   183  		{spec: "*/*", quality: 0.1, specificity: 1, order: 2},
   184  	})
   185  }
   186  
   187  // go test -v -run=^$ -bench=Benchmark_App_ETag -benchmem -count=4
   188  func Benchmark_Utils_ETag(b *testing.B) {
   189  	app := New()
   190  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   191  	defer app.ReleaseCtx(c)
   192  	err := c.SendString("Hello, World!")
   193  	utils.AssertEqual(b, nil, err)
   194  	for n := 0; n < b.N; n++ {
   195  		setETag(c, false)
   196  	}
   197  	utils.AssertEqual(b, `"13-1831710635"`, string(c.Response().Header.Peek(HeaderETag)))
   198  }
   199  
   200  // go test -v -run=Test_Utils_ETag_Weak -count=1
   201  func Test_Utils_ETag_Weak(t *testing.T) {
   202  	t.Parallel()
   203  	app := New()
   204  	t.Run("Set Weak", func(t *testing.T) {
   205  		t.Parallel()
   206  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
   207  		defer app.ReleaseCtx(c)
   208  		err := c.SendString("Hello, World!")
   209  		utils.AssertEqual(t, nil, err)
   210  		setETag(c, true)
   211  		utils.AssertEqual(t, `W/"13-1831710635"`, string(c.Response().Header.Peek(HeaderETag)))
   212  	})
   213  
   214  	t.Run("Match Weak ETag", func(t *testing.T) {
   215  		t.Parallel()
   216  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
   217  		defer app.ReleaseCtx(c)
   218  		err := c.SendString("Hello, World!")
   219  		utils.AssertEqual(t, nil, err)
   220  		c.Request().Header.Set(HeaderIfNoneMatch, `W/"13-1831710635"`)
   221  		setETag(c, true)
   222  		utils.AssertEqual(t, 304, c.Response().StatusCode())
   223  		utils.AssertEqual(t, "", string(c.Response().Header.Peek(HeaderETag)))
   224  		utils.AssertEqual(t, "", string(c.Response().Body()))
   225  	})
   226  
   227  	t.Run("Not Match Weak ETag", func(t *testing.T) {
   228  		t.Parallel()
   229  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
   230  		defer app.ReleaseCtx(c)
   231  		err := c.SendString("Hello, World!")
   232  		utils.AssertEqual(t, nil, err)
   233  		c.Request().Header.Set(HeaderIfNoneMatch, `W/"13-1831710635xx"`)
   234  		setETag(c, true)
   235  		utils.AssertEqual(t, `W/"13-1831710635"`, string(c.Response().Header.Peek(HeaderETag)))
   236  	})
   237  }
   238  
   239  func Test_Utils_UniqueRouteStack(t *testing.T) {
   240  	t.Parallel()
   241  	route1 := &Route{}
   242  	route2 := &Route{}
   243  	route3 := &Route{}
   244  	utils.AssertEqual(
   245  		t,
   246  		[]*Route{
   247  			route1,
   248  			route2,
   249  			route3,
   250  		},
   251  		uniqueRouteStack([]*Route{
   252  			route1,
   253  			route1,
   254  			route1,
   255  			route2,
   256  			route2,
   257  			route2,
   258  			route3,
   259  			route3,
   260  			route3,
   261  			route1,
   262  			route2,
   263  			route3,
   264  		}),
   265  	)
   266  }
   267  
   268  // go test -v -run=^$ -bench=Benchmark_App_ETag_Weak -benchmem -count=4
   269  func Benchmark_Utils_ETag_Weak(b *testing.B) {
   270  	app := New()
   271  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   272  	defer app.ReleaseCtx(c)
   273  	err := c.SendString("Hello, World!")
   274  	utils.AssertEqual(b, nil, err)
   275  	for n := 0; n < b.N; n++ {
   276  		setETag(c, true)
   277  	}
   278  	utils.AssertEqual(b, `W/"13-1831710635"`, string(c.Response().Header.Peek(HeaderETag)))
   279  }
   280  
   281  func Test_Utils_getGroupPath(t *testing.T) {
   282  	t.Parallel()
   283  	res := getGroupPath("/v1", "/")
   284  	utils.AssertEqual(t, "/v1/", res)
   285  
   286  	res = getGroupPath("/v1/", "/")
   287  	utils.AssertEqual(t, "/v1/", res)
   288  
   289  	res = getGroupPath("/", "/")
   290  	utils.AssertEqual(t, "/", res)
   291  
   292  	res = getGroupPath("/v1/api/", "/")
   293  	utils.AssertEqual(t, "/v1/api/", res)
   294  
   295  	res = getGroupPath("/v1/api", "group")
   296  	utils.AssertEqual(t, "/v1/api/group", res)
   297  
   298  	res = getGroupPath("/v1/api", "")
   299  	utils.AssertEqual(t, "/v1/api", res)
   300  }
   301  
   302  // go test -v -run=^$ -bench=Benchmark_Utils_ -benchmem -count=3
   303  
   304  func Benchmark_Utils_getGroupPath(b *testing.B) {
   305  	var res string
   306  	for n := 0; n < b.N; n++ {
   307  		_ = getGroupPath("/v1/long/path/john/doe", "/why/this/name/is/so/awesome")
   308  		_ = getGroupPath("/v1", "/")
   309  		_ = getGroupPath("/v1", "/api")
   310  		res = getGroupPath("/v1", "/api/register/:project")
   311  	}
   312  	utils.AssertEqual(b, "/v1/api/register/:project", res)
   313  }
   314  
   315  func Benchmark_Utils_Unescape(b *testing.B) {
   316  	unescaped := ""
   317  	dst := make([]byte, 0)
   318  
   319  	for n := 0; n < b.N; n++ {
   320  		source := "/cr%C3%A9er"
   321  		pathBytes := utils.UnsafeBytes(source)
   322  		pathBytes = fasthttp.AppendUnquotedArg(dst[:0], pathBytes)
   323  		unescaped = utils.UnsafeString(pathBytes)
   324  	}
   325  
   326  	utils.AssertEqual(b, "/créer", unescaped)
   327  }
   328  
   329  func Test_Utils_Parse_Address(t *testing.T) {
   330  	t.Parallel()
   331  	testCases := []struct {
   332  		addr, host, port string
   333  	}{
   334  		{"[::1]:3000", "[::1]", "3000"},
   335  		{"127.0.0.1:3000", "127.0.0.1", "3000"},
   336  		{"/path/to/unix/socket", "/path/to/unix/socket", ""},
   337  	}
   338  
   339  	for _, c := range testCases {
   340  		host, port := parseAddr(c.addr)
   341  		utils.AssertEqual(t, c.host, host, "addr host")
   342  		utils.AssertEqual(t, c.port, port, "addr port")
   343  	}
   344  }
   345  
   346  func Test_Utils_TestConn_Deadline(t *testing.T) {
   347  	t.Parallel()
   348  	conn := &testConn{}
   349  	utils.AssertEqual(t, nil, conn.SetDeadline(time.Time{}))
   350  	utils.AssertEqual(t, nil, conn.SetReadDeadline(time.Time{}))
   351  	utils.AssertEqual(t, nil, conn.SetWriteDeadline(time.Time{}))
   352  }
   353  
   354  func Test_Utils_IsNoCache(t *testing.T) {
   355  	t.Parallel()
   356  	testCases := []struct {
   357  		string
   358  		bool
   359  	}{
   360  		{"public", false},
   361  		{"no-cache", true},
   362  		{"public, no-cache, max-age=30", true},
   363  		{"public,no-cache", true},
   364  		{"public,no-cacheX", false},
   365  		{"no-cache, public", true},
   366  		{"Xno-cache, public", false},
   367  		{"max-age=30, no-cache,public", true},
   368  	}
   369  
   370  	for _, c := range testCases {
   371  		ok := isNoCache(c.string)
   372  		utils.AssertEqual(t, c.bool, ok,
   373  			fmt.Sprintf("want %t, got isNoCache(%s)=%t", c.bool, c.string, ok))
   374  	}
   375  }
   376  
   377  // go test -v -run=^$ -bench=Benchmark_Utils_IsNoCache -benchmem -count=4
   378  func Benchmark_Utils_IsNoCache(b *testing.B) {
   379  	var ok bool
   380  	for i := 0; i < b.N; i++ {
   381  		_ = isNoCache("public")
   382  		_ = isNoCache("no-cache")
   383  		_ = isNoCache("public, no-cache, max-age=30")
   384  		_ = isNoCache("public,no-cache")
   385  		_ = isNoCache("no-cache, public")
   386  		ok = isNoCache("max-age=30, no-cache,public")
   387  	}
   388  	utils.AssertEqual(b, true, ok)
   389  }
   390  
   391  // go test -v -run=^$ -bench=Benchmark_SlashRecognition -benchmem -count=4
   392  func Benchmark_SlashRecognition(b *testing.B) {
   393  	search := "wtf/1234"
   394  	var result bool
   395  	b.Run("indexBytes", func(b *testing.B) {
   396  		result = false
   397  		for i := 0; i < b.N; i++ {
   398  			if strings.IndexByte(search, slashDelimiter) != -1 {
   399  				result = true
   400  			}
   401  		}
   402  		utils.AssertEqual(b, true, result)
   403  	})
   404  	b.Run("forEach", func(b *testing.B) {
   405  		result = false
   406  		c := int32(slashDelimiter)
   407  		for i := 0; i < b.N; i++ {
   408  			for _, b := range search {
   409  				if b == c {
   410  					result = true
   411  					break
   412  				}
   413  			}
   414  		}
   415  		utils.AssertEqual(b, true, result)
   416  	})
   417  	b.Run("IndexRune", func(b *testing.B) {
   418  		result = false
   419  		c := int32(slashDelimiter)
   420  		for i := 0; i < b.N; i++ {
   421  			result = IndexRune(search, c)
   422  		}
   423  		utils.AssertEqual(b, true, result)
   424  	})
   425  }