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 }