From 0379cc59aad033df2a73d25d8e3b870abe96a55a Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:03:13 -0500 Subject: [PATCH] fix: Inconsistent and flaky unit-tests (#2892) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixes for some of the failing tests * Add readiness check to serverStart() * Use net/http client for tests listen test * Use different key for this test * Run Proxy Middleware tests in parallel. Add nil checks for potential issues pointed by nilaway * Enable parallel client tests * Do not run timing sensitive tests in parallel * Remove TODO * Revert Test_Proxy_DoTimeout_Timeout, and remove t.Parallel() for it * Do not calculate favicon len on each handler call * Revert logic change * Increase timeout of SaveFile tests * Do not run time sensitive tests in parallel * The Agent can't be run in parallel * Do not run time sensitive tests in parallel * Fixes based on uber/nilaway * Revert change to Client test * Run parallel * Update client_test.go * Update client_test.go * Update cache_test.go * Update cookiejar_test.go * Remove parallel for test using timeouts * Remove t.Parallel() from logger middleware tests * Do not use testify.require in a goroutine * Fix import, and update golangci-lint * Remove changes to template_chain.go * Run more tests in parallel * Add more parallel tests * Add more parallel tests * SetLogger can't run in parallel * Run more tests in parallel, fix issue with goroutine in limiter middleware * Update internal/storage/memory, add more benchmarks * Increase sleep for csrf test by 100 milliseconds. Implement asserted and parallel benchmarks for Session middleware * Add 100 milliseconds to sleep during test * Revert name change * fix: Inconsistent and flaky unit-tests * fix: Inconsistent and flaky unit-tests * fix: Inconsistent and flaky unit-tests * fix: Inconsistent and flaky unit-tests * fix: Inconsistent and flaky unit-tests * fix: Inconsistent and flaky unit-tests * fix: Inconsistent and flaky unit-tests * fix: Inconsistent and flaky unit-tests * fix: Inconsistent and flaky unit-tests * fix: Inconsistent and flaky unit-tests --------- Co-authored-by: M. Efe Çetin Co-authored-by: René --- .golangci.yml | 2 - app_test.go | 91 ++++--- client/client_test.go | 19 +- client/cookiejar_test.go | 3 +- client/core_test.go | 8 +- client/helper_test.go | 6 +- client/hooks_test.go | 5 +- client/request_test.go | 3 +- client/response_test.go | 3 +- helpers_test.go | 4 + hooks_test.go | 7 +- internal/memory/memory_test.go | 32 +-- internal/storage/memory/config.go | 4 +- internal/storage/memory/memory.go | 34 ++- internal/storage/memory/memory_test.go | 291 ++++++++++++++++++--- listen.go | 15 +- listen_test.go | 53 ++-- log/fiberlog_test.go | 2 +- middleware/cache/cache_test.go | 7 +- middleware/csrf/csrf_test.go | 2 +- middleware/favicon/favicon.go | 27 +- middleware/favicon/favicon_test.go | 3 +- middleware/idempotency/idempotency_test.go | 14 +- middleware/idempotency/locker_test.go | 3 +- middleware/limiter/limiter_test.go | 68 +++-- middleware/logger/logger_test.go | 19 +- middleware/proxy/proxy_test.go | 99 +++---- middleware/session/session_test.go | 147 ++++++++++- mount_test.go | 1 + prefork_test.go | 7 +- redirect_test.go | 4 +- router_test.go | 2 + 32 files changed, 691 insertions(+), 294 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 1f55c987fb..9dfb719117 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -13,8 +13,6 @@ output: linters-settings: testifylint: enable-all: true - disable: - - go-require errcheck: check-type-assertions: true check-blank: true diff --git a/app_test.go b/app_test.go index 68a2e41cdf..68f0413bb1 100644 --- a/app_test.go +++ b/app_test.go @@ -25,6 +25,7 @@ import ( "github.com/gofiber/utils/v2" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/valyala/fasthttp" "github.com/valyala/fasthttp/fasthttputil" @@ -197,6 +198,7 @@ func (*customConstraint) Execute(param string, args ...string) bool { } func Test_App_CustomConstraint(t *testing.T) { + t.Parallel() app := New() app.RegisterCustomConstraint(&customConstraint{}) @@ -821,20 +823,20 @@ func Test_App_ShutdownWithTimeout(t *testing.T) { time.Sleep(5 * time.Second) return c.SendString("body") }) + ln := fasthttputil.NewInmemoryListener() go func() { - require.NoError(t, app.Listener(ln)) + err := app.Listener(ln) + assert.NoError(t, err) }() + time.Sleep(1 * time.Second) go func() { conn, err := ln.Dial() - if err != nil { - t.Errorf("unexepcted error: %v", err) - } + assert.NoError(t, err) - if _, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")); err != nil { - t.Errorf("unexpected error: %v", err) - } + _, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")) + assert.NoError(t, err) }() time.Sleep(1 * time.Second) @@ -866,20 +868,18 @@ func Test_App_ShutdownWithContext(t *testing.T) { ln := fasthttputil.NewInmemoryListener() go func() { - require.NoError(t, app.Listener(ln)) + err := app.Listener(ln) + assert.NoError(t, err) }() time.Sleep(1 * time.Second) go func() { conn, err := ln.Dial() - if err != nil { - t.Errorf("unexepcted error: %v", err) - } + assert.NoError(t, err) - if _, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")); err != nil { - t.Errorf("unexpected error: %v", err) - } + _, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")) + assert.NoError(t, err) }() time.Sleep(1 * time.Second) @@ -903,6 +903,7 @@ func Test_App_ShutdownWithContext(t *testing.T) { // go test -run Test_App_Static_Index_Default func Test_App_Static_Index_Default(t *testing.T) { + t.Parallel() app := New() app.Static("/prefix", "./.github/workflows") @@ -932,6 +933,7 @@ func Test_App_Static_Index_Default(t *testing.T) { // go test -run Test_App_Static_Index func Test_App_Static_Direct(t *testing.T) { + t.Parallel() app := New() app.Static("/", "./.github") @@ -960,6 +962,7 @@ func Test_App_Static_Direct(t *testing.T) { // go test -run Test_App_Static_MaxAge func Test_App_Static_MaxAge(t *testing.T) { + t.Parallel() app := New() app.Static("/", "./.github", Static{MaxAge: 100}) @@ -974,6 +977,7 @@ func Test_App_Static_MaxAge(t *testing.T) { // go test -run Test_App_Static_Custom_CacheControl func Test_App_Static_Custom_CacheControl(t *testing.T) { + t.Parallel() app := New() app.Static("/", "./.github", Static{ModifyResponse: func(c Ctx) error { @@ -994,6 +998,7 @@ func Test_App_Static_Custom_CacheControl(t *testing.T) { // go test -run Test_App_Static_Download func Test_App_Static_Download(t *testing.T) { + t.Parallel() app := New() app.Static("/fiber.png", "./.github/testdata/fs/img/fiber.png", Static{Download: true}) @@ -1008,6 +1013,7 @@ func Test_App_Static_Download(t *testing.T) { // go test -run Test_App_Static_Group func Test_App_Static_Group(t *testing.T) { + t.Parallel() app := New() grp := app.Group("/v1", func(c Ctx) error { @@ -1037,6 +1043,7 @@ func Test_App_Static_Group(t *testing.T) { } func Test_App_Static_Wildcard(t *testing.T) { + t.Parallel() app := New() app.Static("*", "./.github/index.html") @@ -1054,6 +1061,7 @@ func Test_App_Static_Wildcard(t *testing.T) { } func Test_App_Static_Prefix_Wildcard(t *testing.T) { + t.Parallel() app := New() app.Static("/test/*", "./.github/index.html") @@ -1079,6 +1087,7 @@ func Test_App_Static_Prefix_Wildcard(t *testing.T) { } func Test_App_Static_Prefix(t *testing.T) { + t.Parallel() app := New() app.Static("/john", "./.github") @@ -1109,6 +1118,7 @@ func Test_App_Static_Prefix(t *testing.T) { } func Test_App_Static_Trailing_Slash(t *testing.T) { + t.Parallel() app := New() app.Static("/john", "./.github") @@ -1155,6 +1165,7 @@ func Test_App_Static_Trailing_Slash(t *testing.T) { } func Test_App_Static_Next(t *testing.T) { + t.Parallel() app := New() app.Static("/", ".github", Static{ Next: func(c Ctx) bool { @@ -1168,6 +1179,7 @@ func Test_App_Static_Next(t *testing.T) { }) t.Run("app.Static is skipped: invoking Get handler", func(t *testing.T) { + t.Parallel() req := httptest.NewRequest(MethodGet, "/", nil) req.Header.Set("X-Custom-Header", "skip") resp, err := app.Test(req) @@ -1182,6 +1194,7 @@ func Test_App_Static_Next(t *testing.T) { }) t.Run("app.Static is not skipped: serving index.html", func(t *testing.T) { + t.Parallel() req := httptest.NewRequest(MethodGet, "/", nil) req.Header.Set("X-Custom-Header", "don't skip") resp, err := app.Test(req) @@ -1198,6 +1211,7 @@ func Test_App_Static_Next(t *testing.T) { // go test -run Test_App_Mixed_Routes_WithSameLen func Test_App_Mixed_Routes_WithSameLen(t *testing.T) { + t.Parallel() app := New() // middleware @@ -1476,6 +1490,7 @@ func (invalidView) Render(io.Writer, string, any, ...string) error { panic("impl // go test -run Test_App_Init_Error_View func Test_App_Init_Error_View(t *testing.T) { + t.Parallel() app := New(Config{Views: invalidView{}}) defer func() { @@ -1542,23 +1557,23 @@ func Test_App_ReadTimeout(t *testing.T) { time.Sleep(500 * time.Millisecond) conn, err := net.Dial(NetworkTCP4, "127.0.0.1:4004") - require.NoError(t, err) + assert.NoError(t, err) defer func(conn net.Conn) { err := conn.Close() - require.NoError(t, err) + assert.NoError(t, err) }(conn) _, err = conn.Write([]byte("HEAD /read-timeout HTTP/1.1\r\n")) - require.NoError(t, err) + assert.NoError(t, err) buf := make([]byte, 1024) var n int n, err = conn.Read(buf) - require.NoError(t, err) - require.True(t, bytes.Contains(buf[:n], []byte("408 Request Timeout"))) + assert.NoError(t, err) + assert.True(t, bytes.Contains(buf[:n], []byte("408 Request Timeout"))) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":4004", ListenConfig{DisableStartupMessage: true})) @@ -1576,23 +1591,22 @@ func Test_App_BadRequest(t *testing.T) { go func() { time.Sleep(500 * time.Millisecond) conn, err := net.Dial(NetworkTCP4, "127.0.0.1:4005") - require.NoError(t, err) + assert.NoError(t, err) defer func(conn net.Conn) { err := conn.Close() - require.NoError(t, err) + assert.NoError(t, err) }(conn) _, err = conn.Write([]byte("BadRequest\r\n")) - require.NoError(t, err) + assert.NoError(t, err) buf := make([]byte, 1024) var n int n, err = conn.Read(buf) - require.NoError(t, err) - - require.True(t, bytes.Contains(buf[:n], []byte("400 Bad Request"))) - require.NoError(t, app.Shutdown()) + assert.NoError(t, err) + assert.True(t, bytes.Contains(buf[:n], []byte("400 Bad Request"))) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":4005", ListenConfig{DisableStartupMessage: true})) @@ -1612,12 +1626,12 @@ func Test_App_SmallReadBuffer(t *testing.T) { go func() { time.Sleep(500 * time.Millisecond) req, err := http.NewRequestWithContext(context.Background(), MethodGet, "http://127.0.0.1:4006/small-read-buffer", nil) - require.NoError(t, err) + assert.NoError(t, err) var client http.Client resp, err := client.Do(req) - require.NoError(t, err) - require.Equal(t, 431, resp.StatusCode) - require.NoError(t, app.Shutdown()) + assert.NoError(t, err) + assert.Equal(t, 431, resp.StatusCode) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":4006", ListenConfig{DisableStartupMessage: true})) @@ -1755,6 +1769,19 @@ func Test_App_Test_no_timeout_infinitely(t *testing.T) { } } +func Test_App_Test_timeout(t *testing.T) { + t.Parallel() + + app := New() + app.Get("/", func(_ Ctx) error { + time.Sleep(1 * time.Second) + return nil + }) + + _, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), 100*time.Millisecond) + require.Equal(t, errors.New("test: timeout error after 100ms"), err) +} + func Test_App_SetTLSHandler(t *testing.T) { t.Parallel() tlsHandler := &TLSHandler{clientHelloInfo: &tls.ClientHelloInfo{ @@ -1815,6 +1842,7 @@ func TestApp_GetRoutes(t *testing.T) { } func Test_Middleware_Route_Naming_With_Use(t *testing.T) { + t.Parallel() named := "named" app := New() @@ -1874,6 +1902,7 @@ func Test_Middleware_Route_Naming_With_Use(t *testing.T) { } func Test_Route_Naming_Issue_2671_2685(t *testing.T) { + t.Parallel() app := New() app.Get("/", emptyHandler).Name("index") diff --git a/client/client_test.go b/client/client_test.go index 4bf0580006..0f81dda9e0 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -16,6 +16,7 @@ import ( "github.com/gofiber/fiber/v3/addon/retry" "github.com/gofiber/fiber/v3/internal/tlstest" "github.com/gofiber/utils/v2" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/valyala/bytebufferpool" ) @@ -277,8 +278,8 @@ func Test_Client_ConcurrencyRequests(t *testing.T) { go func(m string) { defer wg.Done() resp, err := client.Custom("http://example.com", m) - require.NoError(t, err) - require.Equal(t, "example.com "+m, utils.UnsafeString(resp.RawResponse.Body())) + assert.NoError(t, err) + assert.Equal(t, "example.com "+m, utils.UnsafeString(resp.RawResponse.Body())) }(method) } } @@ -1258,10 +1259,11 @@ func Test_Client_TLS(t *testing.T) { }) go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{ + assert.NoError(t, app.Listener(ln, fiber.ListenConfig{ DisableStartupMessage: true, })) }() + time.Sleep(1 * time.Second) client := New() resp, err := client.SetTLSConfig(clientTLSConf).Get("https://" + ln.Addr().String()) @@ -1291,10 +1293,11 @@ func Test_Client_TLS_Error(t *testing.T) { }) go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{ + assert.NoError(t, app.Listener(ln, fiber.ListenConfig{ DisableStartupMessage: true, })) }() + time.Sleep(1 * time.Second) client := New() resp, err := client.SetTLSConfig(clientTLSConf).Get("https://" + ln.Addr().String()) @@ -1321,10 +1324,11 @@ func Test_Client_TLS_Empty_TLSConfig(t *testing.T) { }) go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{ + assert.NoError(t, app.Listener(ln, fiber.ListenConfig{ DisableStartupMessage: true, })) }() + time.Sleep(1 * time.Second) client := New() resp, err := client.Get("https://" + ln.Addr().String()) @@ -1579,18 +1583,17 @@ func Test_Client_SetProxyURL(t *testing.T) { func Test_Client_SetRetryConfig(t *testing.T) { t.Parallel() - retryConfig := &retry.Config{ InitialInterval: 1 * time.Second, MaxRetryCount: 3, } core, client, req := newCore(), New(), AcquireRequest() - req.SetURL("http://example.com") + req.SetURL("http://exampleretry.com") client.SetRetryConfig(retryConfig) _, err := core.execute(context.Background(), client, req) - require.NoError(t, err) + require.Error(t, err) require.Equal(t, retryConfig.InitialInterval, client.RetryConfig().InitialInterval) require.Equal(t, retryConfig.MaxRetryCount, client.RetryConfig().MaxRetryCount) } diff --git a/client/cookiejar_test.go b/client/cookiejar_test.go index 3b6fdcda83..2b72bdf34a 100644 --- a/client/cookiejar_test.go +++ b/client/cookiejar_test.go @@ -135,7 +135,6 @@ func TestCookieJarSet(t *testing.T) { func TestCookieJarSetRepeatedCookieKeys(t *testing.T) { t.Parallel() - host := "fast.http" cj := &CookieJar{} @@ -158,7 +157,7 @@ func TestCookieJarSetRepeatedCookieKeys(t *testing.T) { cookies := cj.Get(uri) require.Len(t, cookies, 2) - require.Equal(t, cookies[0], cookie2) + require.Equal(t, cookies[0].String(), cookie2.String()) require.True(t, bytes.Equal(cookies[0].Value(), cookie2.Value())) } diff --git a/client/core_test.go b/client/core_test.go index 2570507a62..b54071da1b 100644 --- a/client/core_test.go +++ b/client/core_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/gofiber/fiber/v3" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/valyala/fasthttp/fasthttputil" ) @@ -48,6 +49,7 @@ func Test_AddMissing_Port(t *testing.T) { }, } for _, tt := range tests { + tt := tt // create a new 'tt' variable for the goroutine t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal(t, tt.want, addMissingPort(tt.args.addr, tt.args.isTLS)) @@ -57,7 +59,6 @@ func Test_AddMissing_Port(t *testing.T) { func Test_Exec_Func(t *testing.T) { t.Parallel() - ln := fasthttputil.NewInmemoryListener() app := fiber.New() @@ -75,7 +76,7 @@ func Test_Exec_Func(t *testing.T) { }) go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{DisableStartupMessage: true})) + assert.NoError(t, app.Listener(ln, fiber.ListenConfig{DisableStartupMessage: true})) }() time.Sleep(300 * time.Millisecond) @@ -134,7 +135,6 @@ func Test_Exec_Func(t *testing.T) { func Test_Execute(t *testing.T) { t.Parallel() - ln := fasthttputil.NewInmemoryListener() app := fiber.New() @@ -152,7 +152,7 @@ func Test_Execute(t *testing.T) { }) go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{DisableStartupMessage: true})) + assert.NoError(t, app.Listener(ln, fiber.ListenConfig{DisableStartupMessage: true})) }() t.Run("add user request hooks", func(t *testing.T) { diff --git a/client/helper_test.go b/client/helper_test.go index 75015c8086..7343fa972f 100644 --- a/client/helper_test.go +++ b/client/helper_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/gofiber/fiber/v3" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/valyala/fasthttp/fasthttputil" ) @@ -29,9 +30,8 @@ func startTestServer(tb testing.TB, beforeStarting func(app *fiber.App)) *testSe ch := make(chan struct{}) go func() { - if err := app.Listener(ln, fiber.ListenConfig{DisableStartupMessage: true}); err != nil { - tb.Fatal(err) - } + err := app.Listener(ln, fiber.ListenConfig{DisableStartupMessage: true}) + assert.NoError(tb, err) close(ch) }() diff --git a/client/hooks_test.go b/client/hooks_test.go index 60721c2c0e..406ee6b83f 100644 --- a/client/hooks_test.go +++ b/client/hooks_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/gofiber/fiber/v3" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -587,7 +588,7 @@ func Test_Client_Logger_Debug(t *testing.T) { addrChan := make(chan string) go func() { - require.NoError(t, app.Listen(":0", fiber.ListenConfig{ + assert.NoError(t, app.Listen(":0", fiber.ListenConfig{ DisableStartupMessage: true, ListenerAddrFunc: func(addr net.Addr) { addrChan <- addr.String() @@ -624,7 +625,7 @@ func Test_Client_Logger_DisableDebug(t *testing.T) { addrChan := make(chan string) go func() { - require.NoError(t, app.Listen(":0", fiber.ListenConfig{ + assert.NoError(t, app.Listen(":0", fiber.ListenConfig{ DisableStartupMessage: true, ListenerAddrFunc: func(addr net.Addr) { addrChan <- addr.String() diff --git a/client/request_test.go b/client/request_test.go index d96c9e8a88..d0348bfeb4 100644 --- a/client/request_test.go +++ b/client/request_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/gofiber/fiber/v3" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/valyala/fasthttp" "github.com/valyala/fasthttp/fasthttputil" @@ -1245,7 +1246,7 @@ func Test_Request_MaxRedirects(t *testing.T) { return c.SendString("redirect") }) - go func() { require.NoError(t, app.Listener(ln, fiber.ListenConfig{DisableStartupMessage: true})) }() + go func() { assert.NoError(t, app.Listener(ln, fiber.ListenConfig{DisableStartupMessage: true})) }() t.Run("success", func(t *testing.T) { t.Parallel() diff --git a/client/response_test.go b/client/response_test.go index eae52c064e..ab22ab388a 100644 --- a/client/response_test.go +++ b/client/response_test.go @@ -12,6 +12,7 @@ import ( "github.com/gofiber/fiber/v3/internal/tlstest" "github.com/gofiber/fiber/v3" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -158,7 +159,7 @@ func Test_Response_Protocol(t *testing.T) { }) go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{ + assert.NoError(t, app.Listener(ln, fiber.ListenConfig{ DisableStartupMessage: true, })) }() diff --git a/helpers_test.go b/helpers_test.go index ee0caa80b3..a905cf64ba 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -212,6 +212,7 @@ func Benchmark_Utils_ParamsMatch(b *testing.B) { } func Test_Utils_AcceptsOfferType(t *testing.T) { + t.Parallel() testCases := []struct { description string spec string @@ -273,6 +274,7 @@ func Test_Utils_AcceptsOfferType(t *testing.T) { } func Test_Utils_GetSplicedStrList(t *testing.T) { + t.Parallel() testCases := []struct { description string headerValue string @@ -302,6 +304,8 @@ func Test_Utils_GetSplicedStrList(t *testing.T) { for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { + tc := tc // create a new 'tc' variable for the goroutine + t.Parallel() dst := make([]string, 10) result := getSplicedStrList(tc.headerValue, dst) require.Equal(t, tc.expectedList, result) diff --git a/hooks_test.go b/hooks_test.go index 91ad87bef7..f96f570706 100644 --- a/hooks_test.go +++ b/hooks_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/valyala/bytebufferpool" ) @@ -215,7 +216,7 @@ func Test_Hook_OnListen(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":9000")) @@ -238,7 +239,7 @@ func Test_Hook_OnListenPrefork(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":9000", ListenConfig{DisableStartupMessage: true, EnablePrefork: true})) @@ -254,7 +255,7 @@ func Test_Hook_OnHook(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() app.Hooks().OnFork(func(pid int) error { diff --git a/internal/memory/memory_test.go b/internal/memory/memory_test.go index 76a751b78d..b4a1983e4c 100644 --- a/internal/memory/memory_test.go +++ b/internal/memory/memory_test.go @@ -9,48 +9,50 @@ import ( ) // go test -run Test_Memory -v -race - func Test_Memory(t *testing.T) { t.Parallel() store := New() var ( - key = "john" + key = "john-internal" val any = []byte("doe") exp = 1 * time.Second ) + // Set key with value store.Set(key, val, 0) - store.Set(key, val, 0) - result := store.Get(key) require.Equal(t, val, result) + // Get non-existing key result = store.Get("empty") - require.Equal(t, nil, result) + require.Nil(t, result) + // Set key with value and ttl store.Set(key, val, exp) time.Sleep(1100 * time.Millisecond) - result = store.Get(key) - require.Equal(t, nil, result) + require.Nil(t, result) + // Set key with value and no expiration store.Set(key, val, 0) result = store.Get(key) require.Equal(t, val, result) + // Delete key store.Delete(key) result = store.Get(key) - require.Equal(t, nil, result) + require.Nil(t, result) - store.Set("john", val, 0) - store.Set("doe", val, 0) + // Reset all keys + store.Set("john-reset", val, 0) + store.Set("doe-reset", val, 0) store.Reset() - result = store.Get("john") - require.Equal(t, nil, result) - - result = store.Get("doe") - require.Equal(t, nil, result) + // Check if all keys are deleted + result = store.Get("john-reset") + require.Nil(t, result) + result = store.Get("doe-reset") + require.Nil(t, result) } // go test -v -run=^$ -bench=Benchmark_Memory -benchmem -count=4 diff --git a/internal/storage/memory/config.go b/internal/storage/memory/config.go index 07d13edb5b..f4bab841c7 100644 --- a/internal/storage/memory/config.go +++ b/internal/storage/memory/config.go @@ -1,6 +1,8 @@ package memory -import "time" +import ( + "time" +) // Config defines the config for storage. type Config struct { diff --git a/internal/storage/memory/memory.go b/internal/storage/memory/memory.go index 279728f58d..e2f305d28b 100644 --- a/internal/storage/memory/memory.go +++ b/internal/storage/memory/memory.go @@ -44,7 +44,7 @@ func New(config ...Config) *Storage { // Get value by key func (s *Storage) Get(key string) ([]byte, error) { - if len(key) <= 0 { + if len(key) == 0 { return nil, nil } s.mux.RLock() @@ -60,7 +60,7 @@ func (s *Storage) Get(key string) ([]byte, error) { // Set key with value func (s *Storage) Set(key string, val []byte, exp time.Duration) error { // Ain't Nobody Got Time For That - if len(key) <= 0 || len(val) <= 0 { + if len(key) == 0 || len(val) == 0 { return nil } @@ -79,7 +79,7 @@ func (s *Storage) Set(key string, val []byte, exp time.Duration) error { // Delete key by key func (s *Storage) Delete(key string) error { // Ain't Nobody Got Time For That - if len(key) <= 0 { + if len(key) == 0 { return nil } s.mux.Lock() @@ -117,7 +117,7 @@ func (s *Storage) gc() { expired = expired[:0] s.mux.RLock() for id, v := range s.db { - if v.expiry != 0 && v.expiry <= ts { + if v.expiry != 0 && v.expiry < ts { expired = append(expired, id) } } @@ -142,3 +142,29 @@ func (s *Storage) Conn() map[string]entry { defer s.mux.RUnlock() return s.db } + +// Return all the keys +func (s *Storage) Keys() ([][]byte, error) { + s.mux.RLock() + defer s.mux.RUnlock() + + if len(s.db) == 0 { + return nil, nil + } + + ts := utils.Timestamp() + keys := make([][]byte, 0, len(s.db)) + for key, v := range s.db { + // Filter out the expired keys + if v.expiry == 0 || v.expiry > ts { + keys = append(keys, []byte(key)) + } + } + + // Double check if no valid keys were found + if len(keys) == 0 { + return nil, nil + } + + return keys, nil +} diff --git a/internal/storage/memory/memory_test.go b/internal/storage/memory/memory_test.go index 7e70b55dfb..347e9f5f47 100644 --- a/internal/storage/memory/memory_test.go +++ b/internal/storage/memory/memory_test.go @@ -4,28 +4,31 @@ import ( "testing" "time" - "github.com/gofiber/utils/v2" "github.com/stretchr/testify/require" ) -var testStore = New() - func Test_Storage_Memory_Set(t *testing.T) { t.Parallel() var ( - key = "john" - val = []byte("doe") + testStore = New() + key = "john" + val = []byte("doe") ) err := testStore.Set(key, val, 0) require.NoError(t, err) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Len(t, keys, 1) } func Test_Storage_Memory_Set_Override(t *testing.T) { t.Parallel() var ( - key = "john" - val = []byte("doe") + testStore = New() + key = "john" + val = []byte("doe") ) err := testStore.Set(key, val, 0) @@ -33,13 +36,18 @@ func Test_Storage_Memory_Set_Override(t *testing.T) { err = testStore.Set(key, val, 0) require.NoError(t, err) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Len(t, keys, 1) } func Test_Storage_Memory_Get(t *testing.T) { t.Parallel() var ( - key = "john" - val = []byte("doe") + testStore = New() + key = "john" + val = []byte("doe") ) err := testStore.Set(key, val, 0) @@ -48,11 +56,18 @@ func Test_Storage_Memory_Get(t *testing.T) { result, err := testStore.Get(key) require.NoError(t, err) require.Equal(t, val, result) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Len(t, keys, 1) } func Test_Storage_Memory_Set_Expiration(t *testing.T) { t.Parallel() var ( + testStore = New(Config{ + GCInterval: 300 * time.Millisecond, + }) key = "john" val = []byte("doe") exp = 1 * time.Second @@ -61,45 +76,92 @@ func Test_Storage_Memory_Set_Expiration(t *testing.T) { err := testStore.Set(key, val, exp) require.NoError(t, err) - time.Sleep(1100 * time.Millisecond) + // interval + expire + buffer + time.Sleep(1500 * time.Millisecond) + + result, err := testStore.Get(key) + require.NoError(t, err) + require.Zero(t, len(result)) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Nil(t, keys) } -func Test_Storage_Memory_Get_Expired(t *testing.T) { - key := "john" +func Test_Storage_Memory_Set_Long_Expiration_with_Keys(t *testing.T) { + t.Parallel() + var ( + testStore = New() + key = "john" + val = []byte("doe") + exp = 3 * time.Second + ) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Nil(t, keys) + + err = testStore.Set(key, val, exp) + require.NoError(t, err) + + time.Sleep(1100 * time.Millisecond) + keys, err = testStore.Keys() + require.NoError(t, err) + require.Len(t, keys, 1) + + time.Sleep(4000 * time.Millisecond) result, err := testStore.Get(key) require.NoError(t, err) - require.Empty(t, result) + require.Zero(t, len(result)) + + keys, err = testStore.Keys() + require.NoError(t, err) + require.Nil(t, keys) } func Test_Storage_Memory_Get_NotExist(t *testing.T) { t.Parallel() - + testStore := New() result, err := testStore.Get("notexist") require.NoError(t, err) - require.Empty(t, result) + require.Zero(t, len(result)) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Nil(t, keys) } func Test_Storage_Memory_Delete(t *testing.T) { t.Parallel() var ( - key = "john" - val = []byte("doe") + testStore = New() + key = "john" + val = []byte("doe") ) err := testStore.Set(key, val, 0) require.NoError(t, err) + keys, err := testStore.Keys() + require.NoError(t, err) + require.Len(t, keys, 1) + err = testStore.Delete(key) require.NoError(t, err) result, err := testStore.Get(key) require.NoError(t, err) - require.Empty(t, result) + require.Zero(t, len(result)) + + keys, err = testStore.Keys() + require.NoError(t, err) + require.Nil(t, keys) } func Test_Storage_Memory_Reset(t *testing.T) { t.Parallel() + testStore := New() val := []byte("doe") err := testStore.Set("john1", val, 0) @@ -108,52 +170,195 @@ func Test_Storage_Memory_Reset(t *testing.T) { err = testStore.Set("john2", val, 0) require.NoError(t, err) + keys, err := testStore.Keys() + require.NoError(t, err) + require.Len(t, keys, 2) + err = testStore.Reset() require.NoError(t, err) result, err := testStore.Get("john1") require.NoError(t, err) - require.Empty(t, result) + require.Zero(t, len(result)) result, err = testStore.Get("john2") require.NoError(t, err) - require.Empty(t, result) + require.Zero(t, len(result)) + + keys, err = testStore.Keys() + require.NoError(t, err) + require.Nil(t, keys) } func Test_Storage_Memory_Close(t *testing.T) { t.Parallel() + testStore := New() require.NoError(t, testStore.Close()) } func Test_Storage_Memory_Conn(t *testing.T) { t.Parallel() + testStore := New() require.NotNil(t, testStore.Conn()) } -// go test -v -run=^$ -bench=Benchmark_Storage_Memory -benchmem -count=4 -func Benchmark_Storage_Memory(b *testing.B) { - keyLength := 1000 - keys := make([]string, keyLength) - for i := 0; i < keyLength; i++ { - keys[i] = utils.UUID() +// Benchmarks for Set operation +func Benchmark_Memory_Set(b *testing.B) { + testStore := New() + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _ = testStore.Set("john", []byte("doe"), 0) //nolint: errcheck // error not needed for benchmark + } +} + +func Benchmark_Memory_Set_Parallel(b *testing.B) { + testStore := New() + b.ReportAllocs() + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + _ = testStore.Set("john", []byte("doe"), 0) //nolint: errcheck // error not needed for benchmark + } + }) +} + +func Benchmark_Memory_Set_Asserted(b *testing.B) { + testStore := New() + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + err := testStore.Set("john", []byte("doe"), 0) + require.NoError(b, err) + } +} + +func Benchmark_Memory_Set_Asserted_Parallel(b *testing.B) { + testStore := New() + b.ReportAllocs() + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + err := testStore.Set("john", []byte("doe"), 0) + require.NoError(b, err) + } + }) +} + +// Benchmarks for Get operation +func Benchmark_Memory_Get(b *testing.B) { + testStore := New() + err := testStore.Set("john", []byte("doe"), 0) + require.NoError(b, err) + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, _ = testStore.Get("john") //nolint: errcheck // error not needed for benchmark + } +} + +func Benchmark_Memory_Get_Parallel(b *testing.B) { + testStore := New() + err := testStore.Set("john", []byte("doe"), 0) + require.NoError(b, err) + + b.ReportAllocs() + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + _, _ = testStore.Get("john") //nolint: errcheck // error not needed for benchmark + } + }) +} + +func Benchmark_Memory_Get_Asserted(b *testing.B) { + testStore := New() + err := testStore.Set("john", []byte("doe"), 0) + require.NoError(b, err) + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, err := testStore.Get("john") + require.NoError(b, err) + } +} + +func Benchmark_Memory_Get_Asserted_Parallel(b *testing.B) { + testStore := New() + err := testStore.Set("john", []byte("doe"), 0) + require.NoError(b, err) + + b.ReportAllocs() + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + _, err := testStore.Get("john") + require.NoError(b, err) + } + }) +} + +// Benchmarks for SetAndDelete operation +func Benchmark_Memory_SetAndDelete(b *testing.B) { + testStore := New() + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _ = testStore.Set("john", []byte("doe"), 0) //nolint: errcheck // error not needed for benchmark + _ = testStore.Delete("john") //nolint: errcheck // error not needed for benchmark } - value := []byte("joe") - - ttl := 2 * time.Second - b.Run("fiber_memory", func(b *testing.B) { - d := New() - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - for _, key := range keys { - d.Set(key, value, ttl) - } - for _, key := range keys { - _, _ = d.Get(key) - } - for _, key := range keys { - d.Delete(key) - } +} + +func Benchmark_Memory_SetAndDelete_Parallel(b *testing.B) { + testStore := New() + b.ReportAllocs() + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + _ = testStore.Set("john", []byte("doe"), 0) //nolint: errcheck // error not needed for benchmark + _ = testStore.Delete("john") //nolint: errcheck // error not needed for benchmark + } + }) +} + +func Benchmark_Memory_SetAndDelete_Asserted(b *testing.B) { + testStore := New() + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + err := testStore.Set("john", []byte("doe"), 0) + require.NoError(b, err) + + err = testStore.Delete("john") + require.NoError(b, err) + } +} + +func Benchmark_Memory_SetAndDelete_Asserted_Parallel(b *testing.B) { + testStore := New() + b.ReportAllocs() + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + err := testStore.Set("john", []byte("doe"), 0) + require.NoError(b, err) + + err = testStore.Delete("john") + require.NoError(b, err) } }) } diff --git a/listen.go b/listen.go index e293a1ef7c..43759393d4 100644 --- a/listen.go +++ b/listen.go @@ -268,16 +268,17 @@ func (*App) createListener(addr string, tlsConfig *tls.Config, cfg ListenConfig) listener, err = net.Listen(cfg.ListenerNetwork, addr) } - if cfg.ListenerAddrFunc != nil { - cfg.ListenerAddrFunc(listener.Addr()) + // Check for error before using the listener + if err != nil { + // Wrap the error from tls.Listen/net.Listen + return nil, fmt.Errorf("failed to listen: %w", err) } - // Wrap error comes from tls.Listen/net.Listen - if err != nil { - err = fmt.Errorf("failed to listen: %w", err) + if cfg.ListenerAddrFunc != nil { + cfg.ListenerAddrFunc(listener.Addr()) } - return listener, err + return listener, nil } func (app *App) printMessages(cfg ListenConfig, ln net.Listener) { @@ -378,7 +379,7 @@ func (app *App) startupMessage(addr string, isTLS bool, pids string, cfg ListenC if cfg.EnablePrefork { // Turn the `pids` variable (in the form ",a,b,c,d,e,f,etc") into a slice of PIDs - var pidSlice []string + pidSlice := make([]string, 0) for _, v := range strings.Split(pids, ",") { if v != "" { pidSlice = append(pidSlice, v) diff --git a/listen_test.go b/listen_test.go index a5d419ac86..762fe8291d 100644 --- a/listen_test.go +++ b/listen_test.go @@ -16,6 +16,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/valyala/fasthttp" "github.com/valyala/fasthttp/fasthttputil" @@ -29,7 +30,7 @@ func Test_Listen(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":4003", ListenConfig{DisableStartupMessage: true})) @@ -47,12 +48,13 @@ func Test_Listen_Graceful_Shutdown(t *testing.T) { }) ln := fasthttputil.NewInmemoryListener() + errs := make(chan error) go func() { - ctx, cancel := context.WithTimeout(context.Background(), 250*time.Millisecond) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() - err := app.Listener(ln, ListenConfig{ + errs <- app.Listener(ln, ListenConfig{ DisableStartupMessage: true, GracefulContext: ctx, OnShutdownSuccess: func() { @@ -61,18 +63,30 @@ func Test_Listen_Graceful_Shutdown(t *testing.T) { mu.Unlock() }, }) - - require.NoError(t, err) }() + // Server readiness check + for i := 0; i < 10; i++ { + conn, err := ln.Dial() + if err == nil { + conn.Close() //nolint:errcheck // ignore error + break + } + // Wait a bit before retrying + time.Sleep(100 * time.Millisecond) + if i == 9 { + t.Fatalf("Server did not become ready in time: %v", err) + } + } + testCases := []struct { Time time.Duration ExpectedBody string ExpectedStatusCode int ExpectedErr error }{ - {Time: 100 * time.Millisecond, ExpectedBody: "example.com", ExpectedStatusCode: StatusOK, ExpectedErr: nil}, - {Time: 500 * time.Millisecond, ExpectedBody: "", ExpectedStatusCode: StatusOK, ExpectedErr: errors.New("InmemoryListener is already closed: use of closed network connection")}, + {Time: 500 * time.Millisecond, ExpectedBody: "example.com", ExpectedStatusCode: StatusOK, ExpectedErr: nil}, + {Time: 3 * time.Second, ExpectedBody: "", ExpectedStatusCode: StatusOK, ExpectedErr: errors.New("InmemoryListener is already closed: use of closed network connection")}, } for _, tc := range testCases { @@ -96,7 +110,9 @@ func Test_Listen_Graceful_Shutdown(t *testing.T) { } mu.Lock() + err := <-errs require.True(t, shutdown) + require.NoError(t, err) mu.Unlock() } @@ -121,7 +137,7 @@ func Test_Listen_TLS(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":0", ListenConfig{ @@ -146,7 +162,7 @@ func Test_Listen_TLS_Prefork(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":99999", ListenConfig{ @@ -170,7 +186,7 @@ func Test_Listen_MutualTLS(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":0", ListenConfig{ @@ -197,7 +213,7 @@ func Test_Listen_MutualTLS_Prefork(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":99999", ListenConfig{ @@ -215,7 +231,7 @@ func Test_Listener(t *testing.T) { go func() { time.Sleep(500 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() ln := fasthttputil.NewInmemoryListener() @@ -223,7 +239,6 @@ func Test_Listener(t *testing.T) { } func Test_App_Listener_TLS_Listener(t *testing.T) { - t.Parallel() // Create tls certificate cer, err := tls.LoadX509KeyPair("./.github/testdata/ssl.pem", "./.github/testdata/ssl.key") if err != nil { @@ -240,7 +255,7 @@ func Test_App_Listener_TLS_Listener(t *testing.T) { go func() { time.Sleep(time.Millisecond * 500) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listener(ln)) @@ -253,7 +268,7 @@ func Test_Listen_TLSConfigFunc(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":0", ListenConfig{ @@ -275,7 +290,7 @@ func Test_Listen_ListenerAddrFunc(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":0", ListenConfig{ @@ -297,7 +312,7 @@ func Test_Listen_BeforeServeFunc(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() wantErr := errors.New("test") @@ -320,7 +335,7 @@ func Test_Listen_ListenerNetwork(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":0", ListenConfig{ @@ -335,7 +350,7 @@ func Test_Listen_ListenerNetwork(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.Listen(":0", ListenConfig{ diff --git a/log/fiberlog_test.go b/log/fiberlog_test.go index ca6e93c83a..315afe7290 100644 --- a/log/fiberlog_test.go +++ b/log/fiberlog_test.go @@ -9,6 +9,7 @@ import ( ) func Test_DefaultSystemLogger(t *testing.T) { + t.Parallel() defaultL := DefaultLogger() require.Equal(t, logger, defaultL) } @@ -24,7 +25,6 @@ func Test_SetLogger(t *testing.T) { } func Test_Fiberlog_SetLevel(t *testing.T) { - // Set up mockLogger := &defaultLogger{} SetLogger(mockLogger) diff --git a/middleware/cache/cache_test.go b/middleware/cache/cache_test.go index 1beee76d62..8966ec7ac2 100644 --- a/middleware/cache/cache_test.go +++ b/middleware/cache/cache_test.go @@ -45,7 +45,6 @@ func Test_Cache_CacheControl(t *testing.T) { func Test_Cache_Expired(t *testing.T) { t.Parallel() - app := fiber.New() app.Use(New(Config{Expiration: 2 * time.Second})) @@ -411,7 +410,6 @@ func Test_Cache_Post(t *testing.T) { func Test_Cache_NothingToCache(t *testing.T) { t.Parallel() - app := fiber.New() app.Use(New(Config{Expiration: -(time.Second * 1)})) @@ -499,7 +497,6 @@ func Test_CustomKey(t *testing.T) { func Test_CustomExpiration(t *testing.T) { t.Parallel() - app := fiber.New() var called bool var newCacheTime int @@ -522,7 +519,7 @@ func Test_CustomExpiration(t *testing.T) { require.Equal(t, 1, newCacheTime) // Sleep until the cache is expired - time.Sleep(1 * time.Second) + time.Sleep(1*time.Second + 100*time.Millisecond) cachedResp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) require.NoError(t, err) @@ -713,7 +710,6 @@ func stableAscendingExpiration() func(c1 fiber.Ctx, c2 *Config) time.Duration { func Test_Cache_MaxBytesOrder(t *testing.T) { t.Parallel() - app := fiber.New() app.Use(New(Config{ MaxBytes: 2, @@ -750,7 +746,6 @@ func Test_Cache_MaxBytesOrder(t *testing.T) { func Test_Cache_MaxBytesSizes(t *testing.T) { t.Parallel() - app := fiber.New() app.Use(New(Config{ diff --git a/middleware/csrf/csrf_test.go b/middleware/csrf/csrf_test.go index 99cbf85e48..e4a91fd2b2 100644 --- a/middleware/csrf/csrf_test.go +++ b/middleware/csrf/csrf_test.go @@ -261,7 +261,7 @@ func Test_CSRF_ExpiredToken_WithSession(t *testing.T) { require.Equal(t, 200, ctx.Response.StatusCode()) // Wait for the token to expire - time.Sleep(1 * time.Second) + time.Sleep(1*time.Second + 100*time.Millisecond) // Expired CSRF token ctx.Request.Reset() diff --git a/middleware/favicon/favicon.go b/middleware/favicon/favicon.go index 66fb6e6000..f1de00cb3d 100644 --- a/middleware/favicon/favicon.go +++ b/middleware/favicon/favicon.go @@ -82,16 +82,18 @@ func New(config ...Config) fiber.Handler { } } - // Load icon if provided + // Load iconData if provided var ( - err error - icon []byte - iconLen string + err error + iconData []byte + iconLenHeader string + iconLen int ) if cfg.Data != nil { // use the provided favicon data - icon = cfg.Data - iconLen = strconv.Itoa(len(cfg.Data)) + iconData = cfg.Data + iconLenHeader = strconv.Itoa(len(cfg.Data)) + iconLen = len(cfg.Data) } else if cfg.File != "" { // read from configured filesystem if present if cfg.FileSystem != nil { @@ -99,14 +101,15 @@ func New(config ...Config) fiber.Handler { if err != nil { panic(err) } - if icon, err = io.ReadAll(f); err != nil { + if iconData, err = io.ReadAll(f); err != nil { panic(err) } - } else if icon, err = os.ReadFile(cfg.File); err != nil { + } else if iconData, err = os.ReadFile(cfg.File); err != nil { panic(err) } - iconLen = strconv.Itoa(len(icon)) + iconLenHeader = strconv.Itoa(len(iconData)) + iconLen = len(iconData) } // Return new handler @@ -134,11 +137,11 @@ func New(config ...Config) fiber.Handler { } // Serve cached favicon - if len(icon) > 0 { - c.Set(fiber.HeaderContentLength, iconLen) + if iconLen > 0 { + c.Set(fiber.HeaderContentLength, iconLenHeader) c.Set(fiber.HeaderContentType, hType) c.Set(fiber.HeaderCacheControl, cfg.CacheControl) - return c.Status(fiber.StatusOK).Send(icon) + return c.Status(fiber.StatusOK).Send(iconData) } return c.SendStatus(fiber.StatusNoContent) diff --git a/middleware/favicon/favicon_test.go b/middleware/favicon/favicon_test.go index ecf550b2a3..5c2fe618d6 100644 --- a/middleware/favicon/favicon_test.go +++ b/middleware/favicon/favicon_test.go @@ -47,7 +47,8 @@ func Test_Middleware_Favicon_Not_Found(t *testing.T) { t.Parallel() defer func() { if err := recover(); err == nil { - t.Fatal("should cache panic") + t.Error("should cache panic") + return } }() diff --git a/middleware/idempotency/idempotency_test.go b/middleware/idempotency/idempotency_test.go index a0e8dce69a..f8a4030a1e 100644 --- a/middleware/idempotency/idempotency_test.go +++ b/middleware/idempotency/idempotency_test.go @@ -14,13 +14,13 @@ import ( "github.com/gofiber/fiber/v3/middleware/idempotency" "github.com/valyala/fasthttp" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // go test -run Test_Idempotency func Test_Idempotency(t *testing.T) { t.Parallel() - app := fiber.New() app.Use(func(c fiber.Ctx) error { @@ -54,7 +54,7 @@ func Test_Idempotency(t *testing.T) { }) // Needs to be at least a second as the memory storage doesn't support shorter durations. - const lifetime = 1 * time.Second + const lifetime = 2 * time.Second app.Use(idempotency.New(idempotency.Config{ Lifetime: lifetime, @@ -75,7 +75,7 @@ func Test_Idempotency(t *testing.T) { }) app.Post("/slow", func(c fiber.Ctx) error { - time.Sleep(2 * lifetime) + time.Sleep(3 * lifetime) return c.SendString(strconv.Itoa(nextCount())) }) @@ -85,7 +85,7 @@ func Test_Idempotency(t *testing.T) { if idempotencyKey != "" { req.Header.Set("X-Idempotency-Key", idempotencyKey) } - resp, err := app.Test(req, 3*lifetime) + resp, err := app.Test(req, 15*time.Second) require.NoError(t, err) body, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -108,7 +108,7 @@ func Test_Idempotency(t *testing.T) { require.Equal(t, "9", doReq(fiber.MethodPost, "/", "11111111-1111-1111-1111-111111111111")) require.Equal(t, "7", doReq(fiber.MethodPost, "/", "00000000-0000-0000-0000-000000000000")) - time.Sleep(2 * lifetime) + time.Sleep(4 * lifetime) require.Equal(t, "10", doReq(fiber.MethodPost, "/", "00000000-0000-0000-0000-000000000000")) require.Equal(t, "10", doReq(fiber.MethodPost, "/", "00000000-0000-0000-0000-000000000000")) @@ -119,13 +119,13 @@ func Test_Idempotency(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - require.Equal(t, "11", doReq(fiber.MethodPost, "/slow", "22222222-2222-2222-2222-222222222222")) + assert.Equal(t, "11", doReq(fiber.MethodPost, "/slow", "22222222-2222-2222-2222-222222222222")) }() } wg.Wait() require.Equal(t, "11", doReq(fiber.MethodPost, "/slow", "22222222-2222-2222-2222-222222222222")) } - time.Sleep(2 * lifetime) + time.Sleep(3 * lifetime) require.Equal(t, "12", doReq(fiber.MethodPost, "/slow", "22222222-2222-2222-2222-222222222222")) } diff --git a/middleware/idempotency/locker_test.go b/middleware/idempotency/locker_test.go index 19589dc7bf..3b4a3ca78a 100644 --- a/middleware/idempotency/locker_test.go +++ b/middleware/idempotency/locker_test.go @@ -6,6 +6,7 @@ import ( "github.com/gofiber/fiber/v3/middleware/idempotency" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -25,7 +26,7 @@ func Test_MemoryLock(t *testing.T) { defer close(done) err := l.Lock("a") - require.NoError(t, err) + assert.NoError(t, err) }() select { diff --git a/middleware/limiter/limiter_test.go b/middleware/limiter/limiter_test.go index 7b88d1d521..ed4470e9a8 100644 --- a/middleware/limiter/limiter_test.go +++ b/middleware/limiter/limiter_test.go @@ -9,6 +9,7 @@ import ( "github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3/internal/storage/memory" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/valyala/fasthttp" ) @@ -16,8 +17,6 @@ import ( // go test -run Test_Limiter_Concurrency_Store -race -v func Test_Limiter_Concurrency_Store(t *testing.T) { t.Parallel() - // Test concurrency using a custom store - app := fiber.New() app.Use(New(Config{ @@ -31,20 +30,19 @@ func Test_Limiter_Concurrency_Store(t *testing.T) { }) var wg sync.WaitGroup - singleRequest := func(wg *sync.WaitGroup) { - defer wg.Done() - resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) - require.NoError(t, err) - require.Equal(t, fiber.StatusOK, resp.StatusCode) - - body, err := io.ReadAll(resp.Body) - require.NoError(t, err) - require.Equal(t, "Hello tester!", string(body)) - } for i := 0; i <= 49; i++ { wg.Add(1) - go singleRequest(&wg) + go func(wg *sync.WaitGroup) { + defer wg.Done() + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) + assert.NoError(t, err) + assert.Equal(t, fiber.StatusOK, resp.StatusCode) + + body, err := io.ReadAll(resp.Body) + assert.NoError(t, err) + assert.Equal(t, "Hello tester!", string(body)) + }(&wg) } wg.Wait() @@ -63,8 +61,6 @@ func Test_Limiter_Concurrency_Store(t *testing.T) { // go test -run Test_Limiter_Concurrency -race -v func Test_Limiter_Concurrency(t *testing.T) { t.Parallel() - // Test concurrency using a default store - app := fiber.New() app.Use(New(Config{ @@ -77,20 +73,19 @@ func Test_Limiter_Concurrency(t *testing.T) { }) var wg sync.WaitGroup - singleRequest := func(wg *sync.WaitGroup) { - defer wg.Done() - resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) - require.NoError(t, err) - require.Equal(t, fiber.StatusOK, resp.StatusCode) - - body, err := io.ReadAll(resp.Body) - require.NoError(t, err) - require.Equal(t, "Hello tester!", string(body)) - } for i := 0; i <= 49; i++ { wg.Add(1) - go singleRequest(&wg) + go func(wg *sync.WaitGroup) { + defer wg.Done() + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) + assert.NoError(t, err) + assert.Equal(t, fiber.StatusOK, resp.StatusCode) + + body, err := io.ReadAll(resp.Body) + assert.NoError(t, err) + assert.Equal(t, "Hello tester!", string(body)) + }(&wg) } wg.Wait() @@ -421,8 +416,6 @@ func Test_Limiter_Sliding_Window_Custom_Storage_Skip_Failed_Requests(t *testing. // go test -run Test_Limiter_Fixed_Window_Skip_Successful_Requests -v func Test_Limiter_Fixed_Window_Skip_Successful_Requests(t *testing.T) { t.Parallel() - // Test concurrency using a default store - app := fiber.New() app.Use(New(Config{ @@ -461,8 +454,6 @@ func Test_Limiter_Fixed_Window_Skip_Successful_Requests(t *testing.T) { // go test -run Test_Limiter_Fixed_Window_Custom_Storage_Skip_Successful_Requests -v func Test_Limiter_Fixed_Window_Custom_Storage_Skip_Successful_Requests(t *testing.T) { t.Parallel() - // Test concurrency using a default store - app := fiber.New() app.Use(New(Config{ @@ -502,8 +493,6 @@ func Test_Limiter_Fixed_Window_Custom_Storage_Skip_Successful_Requests(t *testin // go test -run Test_Limiter_Sliding_Window_Skip_Successful_Requests -v func Test_Limiter_Sliding_Window_Skip_Successful_Requests(t *testing.T) { t.Parallel() - // Test concurrency using a default store - app := fiber.New() app.Use(New(Config{ @@ -542,8 +531,6 @@ func Test_Limiter_Sliding_Window_Skip_Successful_Requests(t *testing.T) { // go test -run Test_Limiter_Sliding_Window_Custom_Storage_Skip_Successful_Requests -v func Test_Limiter_Sliding_Window_Custom_Storage_Skip_Successful_Requests(t *testing.T) { t.Parallel() - // Test concurrency using a default store - app := fiber.New() app.Use(New(Config{ @@ -682,7 +669,7 @@ func Test_Sliding_Window(t *testing.T) { app := fiber.New() app.Use(New(Config{ Max: 10, - Expiration: 2 * time.Second, + Expiration: 1 * time.Second, Storage: memory.New(), LimiterMiddleware: SlidingWindow{}, })) @@ -706,7 +693,7 @@ func Test_Sliding_Window(t *testing.T) { singleRequest(false) } - time.Sleep(2 * time.Second) + time.Sleep(3 * time.Second) for i := 0; i < 5; i++ { singleRequest(false) @@ -718,9 +705,14 @@ func Test_Sliding_Window(t *testing.T) { singleRequest(false) } - time.Sleep(4 * time.Second) + time.Sleep(3 * time.Second) - for i := 0; i < 9; i++ { + for i := 0; i < 10; i++ { singleRequest(false) } + + // requests should fail now + for i := 0; i < 5; i++ { + singleRequest(true) + } } diff --git a/middleware/logger/logger_test.go b/middleware/logger/logger_test.go index daadab4c0e..0aa517bcf5 100644 --- a/middleware/logger/logger_test.go +++ b/middleware/logger/logger_test.go @@ -95,6 +95,7 @@ func Test_Logger_locals(t *testing.T) { func Test_Logger_Next(t *testing.T) { t.Parallel() app := fiber.New() + app.Use(New(Config{ Next: func(_ fiber.Ctx) bool { return true @@ -111,6 +112,7 @@ func Test_Logger_Done(t *testing.T) { t.Parallel() buf := bytes.NewBuffer(nil) app := fiber.New() + app.Use(New(Config{ Done: func(c fiber.Ctx, logString []byte) { if c.Response().StatusCode() == fiber.StatusOK { @@ -133,6 +135,7 @@ func Test_Logger_Done(t *testing.T) { func Test_Logger_ErrorTimeZone(t *testing.T) { t.Parallel() app := fiber.New() + app.Use(New(Config{ TimeZone: "invalid", })) @@ -154,6 +157,7 @@ func Test_Logger_ErrorOutput_WithoutColor(t *testing.T) { t.Parallel() o := new(fakeErrorOutput) app := fiber.New() + app.Use(New(Config{ Output: o, DisableColors: true, @@ -170,6 +174,7 @@ func Test_Logger_ErrorOutput(t *testing.T) { t.Parallel() o := new(fakeErrorOutput) app := fiber.New() + app.Use(New(Config{ Output: o, })) @@ -187,6 +192,7 @@ func Test_Logger_All(t *testing.T) { defer bytebufferpool.Put(buf) app := fiber.New() + app.Use(New(Config{ Format: "${pid}${reqHeaders}${referer}${scheme}${protocol}${ip}${ips}${host}${url}${ua}${body}${route}${black}${red}${green}${yellow}${blue}${magenta}${cyan}${white}${reset}${error}${reqHeader:test}${query:test}${form:test}${cookie:test}${non}", Output: buf, @@ -230,10 +236,10 @@ func getLatencyTimeUnits() []struct { // go test -run Test_Logger_WithLatency func Test_Logger_WithLatency(t *testing.T) { - t.Parallel() buff := bytebufferpool.Get() defer bytebufferpool.Put(buff) app := fiber.New() + logger := New(Config{ Output: buff, Format: "${latency}", @@ -258,7 +264,7 @@ func Test_Logger_WithLatency(t *testing.T) { sleepDuration = 1 * tu.div // Create a new HTTP request to the test route - resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 2*time.Second) + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 3*time.Second) require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode) @@ -273,10 +279,10 @@ func Test_Logger_WithLatency(t *testing.T) { // go test -run Test_Logger_WithLatency_DefaultFormat func Test_Logger_WithLatency_DefaultFormat(t *testing.T) { - t.Parallel() buff := bytebufferpool.Get() defer bytebufferpool.Put(buff) app := fiber.New() + logger := New(Config{ Output: buff, }) @@ -323,6 +329,7 @@ func Test_Query_Params(t *testing.T) { defer bytebufferpool.Put(buf) app := fiber.New() + app.Use(New(Config{ Format: "${queryParams}", Output: buf, @@ -343,6 +350,7 @@ func Test_Response_Body(t *testing.T) { defer bytebufferpool.Put(buf) app := fiber.New() + app.Use(New(Config{ Format: "${resBody}", Output: buf, @@ -496,6 +504,7 @@ func Test_Response_Header(t *testing.T) { defer bytebufferpool.Put(buf) app := fiber.New() + app.Use(requestid.New(requestid.Config{ Next: nil, Header: fiber.HeaderXRequestID, @@ -523,6 +532,7 @@ func Test_Req_Header(t *testing.T) { defer bytebufferpool.Put(buf) app := fiber.New() + app.Use(New(Config{ Format: "${reqHeader:test}", Output: buf, @@ -546,6 +556,7 @@ func Test_ReqHeader_Header(t *testing.T) { defer bytebufferpool.Put(buf) app := fiber.New() + app.Use(New(Config{ Format: "${reqHeader:test}", Output: buf, @@ -571,6 +582,7 @@ func Test_CustomTags(t *testing.T) { defer bytebufferpool.Put(buf) app := fiber.New() + app.Use(New(Config{ Format: "${custom_tag}", CustomTags: map[string]LogFunc{ @@ -644,6 +656,7 @@ func Test_Logger_EnableColors(t *testing.T) { t.Parallel() o := new(fakeOutput) app := fiber.New() + app.Use(New(Config{ Output: o, })) diff --git a/middleware/proxy/proxy_test.go b/middleware/proxy/proxy_test.go index 7734a93335..b9da7af911 100644 --- a/middleware/proxy/proxy_test.go +++ b/middleware/proxy/proxy_test.go @@ -18,6 +18,17 @@ import ( "github.com/valyala/fasthttp" ) +func startServer(app *fiber.App, ln net.Listener) { + go func() { + err := app.Listener(ln, fiber.ListenConfig{ + DisableStartupMessage: true, + }) + if err != nil { + panic(err) + } + }() +} + func createProxyTestServer(t *testing.T, handler fiber.Handler) (*fiber.App, string) { t.Helper() @@ -27,15 +38,10 @@ func createProxyTestServer(t *testing.T, handler fiber.Handler) (*fiber.App, str ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0") require.NoError(t, err) - go func() { - require.NoError(t, target.Listener(ln, fiber.ListenConfig{ - DisableStartupMessage: true, - })) - }() - - time.Sleep(2 * time.Second) addr := ln.Addr().String() + startServer(target, ln) + return target, addr } @@ -45,7 +51,9 @@ func Test_Proxy_Empty_Upstream_Servers(t *testing.T) { defer func() { if r := recover(); r != nil { - require.Equal(t, "Servers cannot be empty", r) + if r != "Servers cannot be empty" { + panic(r) + } } }() app := fiber.New() @@ -58,7 +66,9 @@ func Test_Proxy_Empty_Config(t *testing.T) { defer func() { if r := recover(); r != nil { - require.Equal(t, "Servers cannot be empty", r) + if r != "Servers cannot be empty" { + panic(r) + } } }() app := fiber.New() @@ -132,11 +142,7 @@ func Test_Proxy_Balancer_WithTlsConfig(t *testing.T) { TlsConfig: clientTLSConf, })) - go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{ - DisableStartupMessage: true, - })) - }() + startServer(app, ln) client := clientpkg.New() client.SetTLSConfig(clientTLSConf) @@ -163,18 +169,11 @@ func Test_Proxy_Forward_WithTlsConfig_To_Http(t *testing.T) { require.NoError(t, err) proxyServerLn = tls.NewListener(proxyServerLn, proxyServerTLSConf) - - app := fiber.New() - proxyAddr := proxyServerLn.Addr().String() + app := fiber.New() app.Use(Forward("http://" + targetAddr)) - - go func() { - require.NoError(t, app.Listener(proxyServerLn, fiber.ListenConfig{ - DisableStartupMessage: true, - })) - }() + startServer(app, proxyServerLn) client := clientpkg.New() client.SetTimeout(5 * time.Second) @@ -235,11 +234,7 @@ func Test_Proxy_Forward_WithClient_TLSConfig(t *testing.T) { }) app.Use(Forward("https://" + addr + "/tlsfwd")) - go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{ - DisableStartupMessage: true, - })) - }() + startServer(app, ln) client := clientpkg.New() client.SetTLSConfig(clientTLSConf) @@ -441,7 +436,7 @@ func Test_Proxy_DoRedirects_RestoreOriginalURL(t *testing.T) { return DoRedirects(c, "http://google.com", 1) }) - resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil)) + resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 2*time.Second) require.NoError(t, err1) _, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -479,7 +474,7 @@ func Test_Proxy_DoTimeout_RestoreOriginalURL(t *testing.T) { return DoTimeout(c, "http://"+addr, time.Second) }) - resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil)) + resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 2*time.Second) require.NoError(t, err1) body, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -490,8 +485,6 @@ func Test_Proxy_DoTimeout_RestoreOriginalURL(t *testing.T) { // go test -race -run Test_Proxy_DoTimeout_Timeout func Test_Proxy_DoTimeout_Timeout(t *testing.T) { - t.Parallel() - _, addr := createProxyTestServer(t, func(c fiber.Ctx) error { time.Sleep(time.Second * 5) return c.SendString("proxied") @@ -502,8 +495,14 @@ func Test_Proxy_DoTimeout_Timeout(t *testing.T) { return DoTimeout(c, "http://"+addr, time.Second) }) - _, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 1*time.Second) - require.Equal(t, errors.New("test: timeout error after 1s"), err1) + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 2*time.Second) + require.NoError(t, err) + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + require.Equal(t, "timeout", string(body)) + require.Equal(t, fiber.StatusInternalServerError, resp.StatusCode) + require.Equal(t, "/test", resp.Request.URL.String()) } // go test -race -run Test_Proxy_DoDeadline_RestoreOriginalURL @@ -530,8 +529,6 @@ func Test_Proxy_DoDeadline_RestoreOriginalURL(t *testing.T) { // go test -race -run Test_Proxy_DoDeadline_PastDeadline func Test_Proxy_DoDeadline_PastDeadline(t *testing.T) { - t.Parallel() - _, addr := createProxyTestServer(t, func(c fiber.Ctx) error { time.Sleep(time.Second * 5) return c.SendString("proxied") @@ -539,7 +536,7 @@ func Test_Proxy_DoDeadline_PastDeadline(t *testing.T) { app := fiber.New() app.Get("/test", func(c fiber.Ctx) error { - return DoDeadline(c, "http://"+addr, time.Now().Add(time.Second)) + return DoDeadline(c, "http://"+addr, time.Now().Add(2*time.Second)) }) _, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 1*time.Second) @@ -590,14 +587,9 @@ func Test_Proxy_Forward_Global_Client(t *testing.T) { addr := ln.Addr().String() app.Use(Forward("http://" + addr + "/test_global_client")) - go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{ - DisableStartupMessage: true, - })) - }() + startServer(app, ln) client := clientpkg.New() - resp, err := client.Get("http://" + addr) require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode()) @@ -622,14 +614,9 @@ func Test_Proxy_Forward_Local_Client(t *testing.T) { Dial: fasthttp.Dial, })) - go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{ - DisableStartupMessage: true, - })) - }() + startServer(app, ln) client := clientpkg.New() - resp, err := client.Get("http://" + addr) require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode()) @@ -694,20 +681,10 @@ func Test_Proxy_Domain_Forward_Local(t *testing.T) { Dial: fasthttp.Dial, })) - - go func() { - require.NoError(t, app.Listener(ln, fiber.ListenConfig{ - DisableStartupMessage: true, - })) - }() - go func() { - require.NoError(t, app1.Listener(ln1, fiber.ListenConfig{ - DisableStartupMessage: true, - })) - }() + startServer(app, ln) + startServer(app1, ln1) client := clientpkg.New() - resp, err := client.Get("http://" + localDomain + "/test?query_test=true") require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode()) diff --git a/middleware/session/session_test.go b/middleware/session/session_test.go index ab2741b95e..02bd52d4e2 100644 --- a/middleware/session/session_test.go +++ b/middleware/session/session_test.go @@ -346,8 +346,9 @@ func Test_Session_Save_Expiration(t *testing.T) { t.Parallel() t.Run("save to cookie", func(t *testing.T) { - const sessionDuration = 5 * time.Second t.Parallel() + + const sessionDuration = 5 * time.Second // session store store := New() // fiber instance @@ -634,36 +635,158 @@ func Test_Session_Regenerate(t *testing.T) { // go test -v -run=^$ -bench=Benchmark_Session -benchmem -count=4 func Benchmark_Session(b *testing.B) { - app, store := fiber.New(), New() - c := app.AcquireCtx(&fasthttp.RequestCtx{}) - defer app.ReleaseCtx(c) - c.Request().Header.SetCookie(store.sessionName, "12356789") - - var err error b.Run("default", func(b *testing.B) { + app, store := fiber.New(), New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + c.Request().Header.SetCookie(store.sessionName, "12356789") + b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { sess, _ := store.Get(c) //nolint:errcheck // We're inside a benchmark sess.Set("john", "doe") - err = sess.Save() + _ = sess.Save() //nolint:errcheck // We're inside a benchmark } - - require.NoError(b, err) }) b.Run("storage", func(b *testing.B) { - store = New(Config{ + app := fiber.New() + store := New(Config{ Storage: memory.New(), }) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + c.Request().Header.SetCookie(store.sessionName, "12356789") + b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { sess, _ := store.Get(c) //nolint:errcheck // We're inside a benchmark sess.Set("john", "doe") + _ = sess.Save() //nolint:errcheck // We're inside a benchmark + } + }) +} + +// go test -v -run=^$ -bench=Benchmark_Session_Parallel -benchmem -count=4 +func Benchmark_Session_Parallel(b *testing.B) { + b.Run("default", func(b *testing.B) { + app, store := fiber.New(), New() + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + c.Request().Header.SetCookie(store.sessionName, "12356789") + + sess, _ := store.Get(c) //nolint:errcheck // We're inside a benchmark + sess.Set("john", "doe") + _ = sess.Save() //nolint:errcheck // We're inside a benchmark + app.ReleaseCtx(c) + } + }) + }) + + b.Run("storage", func(b *testing.B) { + app := fiber.New() + store := New(Config{ + Storage: memory.New(), + }) + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + c.Request().Header.SetCookie(store.sessionName, "12356789") + + sess, _ := store.Get(c) //nolint:errcheck // We're inside a benchmark + sess.Set("john", "doe") + _ = sess.Save() //nolint:errcheck // We're inside a benchmark + app.ReleaseCtx(c) + } + }) + }) +} + +// go test -v -run=^$ -bench=Benchmark_Session_Asserted -benchmem -count=4 +func Benchmark_Session_Asserted(b *testing.B) { + b.Run("default", func(b *testing.B) { + app, store := fiber.New(), New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + c.Request().Header.SetCookie(store.sessionName, "12356789") + + b.ReportAllocs() + b.ResetTimer() + for n := 0; n < b.N; n++ { + sess, err := store.Get(c) + require.NoError(b, err) + sess.Set("john", "doe") err = sess.Save() + require.NoError(b, err) } + }) - require.NoError(b, err) + b.Run("storage", func(b *testing.B) { + app := fiber.New() + store := New(Config{ + Storage: memory.New(), + }) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + c.Request().Header.SetCookie(store.sessionName, "12356789") + + b.ReportAllocs() + b.ResetTimer() + for n := 0; n < b.N; n++ { + sess, err := store.Get(c) + require.NoError(b, err) + sess.Set("john", "doe") + err = sess.Save() + require.NoError(b, err) + } + }) +} + +// go test -v -run=^$ -bench=Benchmark_Session_Asserted_Parallel -benchmem -count=4 +func Benchmark_Session_Asserted_Parallel(b *testing.B) { + b.Run("default", func(b *testing.B) { + app, store := fiber.New(), New() + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + c.Request().Header.SetCookie(store.sessionName, "12356789") + + sess, err := store.Get(c) + require.NoError(b, err) + sess.Set("john", "doe") + require.NoError(b, sess.Save()) + app.ReleaseCtx(c) + } + }) + }) + + b.Run("storage", func(b *testing.B) { + app := fiber.New() + store := New(Config{ + Storage: memory.New(), + }) + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + c.Request().Header.SetCookie(store.sessionName, "12356789") + + sess, err := store.Get(c) + require.NoError(b, err) + sess.Set("john", "doe") + require.NoError(b, sess.Save()) + app.ReleaseCtx(c) + } + }) }) } diff --git a/mount_test.go b/mount_test.go index b2c82c2952..cd021b248a 100644 --- a/mount_test.go +++ b/mount_test.go @@ -399,6 +399,7 @@ func Test_App_UseMountedErrorHandlerForBestPrefixMatch(t *testing.T) { // go test -run Test_Mount_Route_Names func Test_Mount_Route_Names(t *testing.T) { + t.Parallel() // create sub-app with 2 handlers: subApp1 := New() subApp1.Get("/users", func(c Ctx) error { diff --git a/prefork_test.go b/prefork_test.go index b71bb56ef0..63cd635acd 100644 --- a/prefork_test.go +++ b/prefork_test.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -28,7 +29,7 @@ func Test_App_Prefork_Child_Process(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.prefork("[::1]:", nil, ListenConfig{ListenerNetwork: NetworkTCP6})) @@ -43,7 +44,7 @@ func Test_App_Prefork_Child_Process(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.prefork("127.0.0.1:", config, listenConfigDefault())) @@ -57,7 +58,7 @@ func Test_App_Prefork_Master_Process(t *testing.T) { go func() { time.Sleep(1000 * time.Millisecond) - require.NoError(t, app.Shutdown()) + assert.NoError(t, app.Shutdown()) }() require.NoError(t, app.prefork(":3000", nil, listenConfigDefault())) diff --git a/redirect_test.go b/redirect_test.go index 6dd2ae6d19..a77bfbc4ec 100644 --- a/redirect_test.go +++ b/redirect_test.go @@ -12,6 +12,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/valyala/fasthttp" "github.com/valyala/fasthttp/fasthttputil" @@ -249,7 +250,6 @@ func Test_Redirect_setFlash(t *testing.T) { // go test -run Test_Redirect_Request func Test_Redirect_Request(t *testing.T) { t.Parallel() - app := New() app.Get("/", func(c Ctx) error { @@ -282,7 +282,7 @@ func Test_Redirect_Request(t *testing.T) { GracefulContext: ctx, }) - require.NoError(t, err) + assert.NoError(t, err) }() // Test cases diff --git a/router_test.go b/router_test.go index 5b29bbc3c2..5d7c95c14c 100644 --- a/router_test.go +++ b/router_test.go @@ -455,6 +455,7 @@ func Test_Route_Static_HasPrefix(t *testing.T) { } func Test_Router_NotFound(t *testing.T) { + t.Parallel() app := New() app.Use(func(c Ctx) error { return c.Next() @@ -472,6 +473,7 @@ func Test_Router_NotFound(t *testing.T) { } func Test_Router_NotFound_HTML_Inject(t *testing.T) { + t.Parallel() app := New() app.Use(func(c Ctx) error { return c.Next()