From 00405f71e81ec14125a3bc1f7f697c485606d088 Mon Sep 17 00:00:00 2001 From: Giovanni Rivera Date: Tue, 1 Oct 2024 15:47:07 -0700 Subject: [PATCH 1/8] =?UTF-8?q?=F0=9F=94=A5=20Feature:=20Add=20thread-safe?= =?UTF-8?q?=20reading=20from=20a=20closed=20testConn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers.go | 33 ++++++++++++++++++++++++++++----- helpers_test.go | 18 ++++++++++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/helpers.go b/helpers.go index 90621b1c42..526074032a 100644 --- a/helpers.go +++ b/helpers.go @@ -613,13 +613,36 @@ func isNoCache(cacheControl string) bool { } type testConn struct { - r bytes.Buffer - w bytes.Buffer + r bytes.Buffer + w bytes.Buffer + isClosed bool + sync.Mutex } -func (c *testConn) Read(b []byte) (int, error) { return c.r.Read(b) } //nolint:wrapcheck // This must not be wrapped -func (c *testConn) Write(b []byte) (int, error) { return c.w.Write(b) } //nolint:wrapcheck // This must not be wrapped -func (*testConn) Close() error { return nil } +func (c *testConn) Read(b []byte) (int, error) { + c.Lock() + defer c.Unlock() + + return c.r.Read(b) //nolint:wrapcheck // This must not be wrapped +} + +func (c *testConn) Write(b []byte) (int, error) { + c.Lock() + defer c.Unlock() + + if c.isClosed { + return 0, errors.New("testConn is closed") + } + return c.w.Write(b) //nolint:wrapcheck // This must not be wrapped +} + +func (c *testConn) Close() error { + c.Lock() + defer c.Unlock() + + c.isClosed = true + return nil +} func (*testConn) LocalAddr() net.Addr { return &net.TCPAddr{Port: 0, Zone: "", IP: net.IPv4zero} } func (*testConn) RemoteAddr() net.Addr { return &net.TCPAddr{Port: 0, Zone: "", IP: net.IPv4zero} } diff --git a/helpers_test.go b/helpers_test.go index ddee434098..375274859f 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -5,6 +5,7 @@ package fiber import ( + "errors" "strings" "testing" "time" @@ -514,6 +515,23 @@ func Test_Utils_TestConn_Deadline(t *testing.T) { require.NoError(t, conn.SetWriteDeadline(time.Time{})) } +func Test_Utils_TestConn_Closed_Write(t *testing.T) { + t.Parallel() + conn := &testConn{} + + _, err := conn.Write([]byte("Hello World")) + require.NoError(t, err) + + conn.Close() + _, err = conn.Write([]byte("This should fail")) + require.ErrorIs(t, err, errors.New("testConn is closed")) + + buffer := make([]byte, 12) + _, err = conn.Read(buffer) + require.NoError(t, err) + require.Equal(t, []byte("Hello World"), buffer) +} + func Test_Utils_IsNoCache(t *testing.T) { t.Parallel() testCases := []struct { From 71c153b29f61562efbf3d288c882768dff3b85ea Mon Sep 17 00:00:00 2001 From: Giovanni Rivera Date: Wed, 2 Oct 2024 13:44:15 -0700 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=94=A5=20Feature:=20Add=20TestConfig?= =?UTF-8?q?=20to=20app.Test()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit is summarized as: - Add the struct `TestConfig` as a parameter for `app.Test()` instead of `timeout` - Add documentation of `TestConfig` to docs/api/app.md and in-line - Modify middleware to use `TestConfig` instead of the previous implementation Fixes #3149 --- app.go | 45 ++++++++++++++---- app_test.go | 36 ++++++++++++-- ctx_test.go | 5 +- docs/api/app.md | 2 +- middleware/compress/compress_test.go | 30 +++++++++--- middleware/idempotency/idempotency_test.go | 5 +- middleware/keyauth/keyauth_test.go | 20 ++++++-- middleware/logger/logger_test.go | 10 +++- middleware/pprof/pprof_test.go | 10 +++- middleware/proxy/proxy_test.go | 55 +++++++++++++++++----- middleware/static/static_test.go | 25 ++++++++-- 11 files changed, 197 insertions(+), 46 deletions(-) diff --git a/app.go b/app.go index e0240d3c16..82ba039a61 100644 --- a/app.go +++ b/app.go @@ -14,6 +14,7 @@ import ( "encoding/xml" "errors" "fmt" + "io" "net" "net/http" "net/http/httputil" @@ -864,13 +865,33 @@ func (app *App) Hooks() *Hooks { return app.hooks } +// TestConfig is a struct holding Test settings +type TestConfig struct { //nolint:govet // Aligning the struct fields is not necessary. betteralign:ignore + // Sets a timeout duration for the test. + // + // Default: time.Second + Timeout time.Duration + + // When set to true, the test will discard the + // current http response and give a timeout error. + // + // Default: true + ErrOnTimeout bool +} + // Test is used for internal debugging by passing a *http.Request. -// Timeout is optional and defaults to 1s, -1 will disable it completely. -func (app *App) Test(req *http.Request, timeout ...time.Duration) (*http.Response, error) { - // Set timeout - to := 1 * time.Second - if len(timeout) > 0 { - to = timeout[0] +// Config is optional and defaults to a 1s error on timeout, +// -1 timeout will disable it completely. +func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, error) { + // Default config + cfg := TestConfig{ + Timeout: time.Second, + ErrOnTimeout: true, + } + + // Override config if provided + if len(config) > 0 { + cfg = config[0] } // Add Content-Length if not provided with body @@ -909,12 +930,15 @@ func (app *App) Test(req *http.Request, timeout ...time.Duration) (*http.Respons }() // Wait for callback - if to >= 0 { + if cfg.Timeout >= 0 { // With timeout select { case err = <-channel: - case <-time.After(to): - return nil, fmt.Errorf("test: timeout error after %s", to) + case <-time.After(cfg.Timeout): + conn.Close() + if cfg.ErrOnTimeout { + return nil, fmt.Errorf("test: timeout error after %s", cfg.Timeout) + } } } else { // Without timeout @@ -932,6 +956,9 @@ func (app *App) Test(req *http.Request, timeout ...time.Duration) (*http.Respons // Convert raw http response to *http.Response res, err := http.ReadResponse(buffer, req) if err != nil { + if err == io.ErrUnexpectedEOF { + return nil, fmt.Errorf("test: got empty response") + } return nil, fmt.Errorf("failed to read response: %w", err) } diff --git a/app_test.go b/app_test.go index 6b493de1eb..507fe999be 100644 --- a/app_test.go +++ b/app_test.go @@ -1124,7 +1124,10 @@ func Test_Test_Timeout(t *testing.T) { app.Get("/", testEmptyHandler) - resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), -1) + resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{ + Timeout: -1, + ErrOnTimeout: false, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -1133,7 +1136,10 @@ func Test_Test_Timeout(t *testing.T) { return nil }) - _, err = app.Test(httptest.NewRequest(MethodGet, "/timeout", nil), 20*time.Millisecond) + _, err = app.Test(httptest.NewRequest(MethodGet, "/timeout", nil), TestConfig{ + Timeout: 20*time.Millisecond, + ErrOnTimeout: true, + }) require.Error(t, err, "app.Test(req)") } @@ -1432,7 +1438,10 @@ func Test_App_Test_no_timeout_infinitely(t *testing.T) { }) req := httptest.NewRequest(MethodGet, "/", nil) - _, err = app.Test(req, -1) + _, err = app.Test(req, TestConfig{ + Timeout: -1, + ErrOnTimeout: true, + }) }() tk := time.NewTimer(5 * time.Second) @@ -1460,10 +1469,29 @@ func Test_App_Test_timeout(t *testing.T) { return nil }) - _, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), 100*time.Millisecond) + _, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{ + Timeout: 100*time.Millisecond, + ErrOnTimeout: true, + }) require.Equal(t, errors.New("test: timeout error after 100ms"), err) } +func Test_App_Test_timeout_empty_response(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), TestConfig{ + Timeout: 100*time.Millisecond, + ErrOnTimeout: false, + }) + require.Equal(t, errors.New("test: got empty response"), err) +} + func Test_App_SetTLSHandler(t *testing.T) { t.Parallel() tlsHandler := &TLSHandler{clientHelloInfo: &tls.ClientHelloInfo{ diff --git a/ctx_test.go b/ctx_test.go index a94e4cb42b..5f0e7d023d 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -3142,7 +3142,10 @@ func Test_Static_Compress(t *testing.T) { req := httptest.NewRequest(MethodGet, "/file", nil) req.Header.Set("Accept-Encoding", algo) - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") diff --git a/docs/api/app.md b/docs/api/app.md index ef9c2ea08d..8b563b5c57 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -540,7 +540,7 @@ func (app *App) SetTLSHandler(tlsHandler *TLSHandler) Testing your application is done with the **Test** method. Use this method for creating `_test.go` files or when you need to debug your routing logic. The default timeout is `1s` if you want to disable a timeout altogether, pass `-1` as a second argument. ```go title="Signature" -func (app *App) Test(req *http.Request, msTimeout ...int) (*http.Response, error) +func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, error) ``` ```go title="Examples" diff --git a/middleware/compress/compress_test.go b/middleware/compress/compress_test.go index f258ba4460..5de1127d66 100644 --- a/middleware/compress/compress_test.go +++ b/middleware/compress/compress_test.go @@ -39,7 +39,10 @@ func Test_Compress_Gzip(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Set("Accept-Encoding", "gzip") - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") require.Equal(t, "gzip", resp.Header.Get(fiber.HeaderContentEncoding)) @@ -72,7 +75,10 @@ func Test_Compress_Different_Level(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Set("Accept-Encoding", algo) - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") require.Equal(t, algo, resp.Header.Get(fiber.HeaderContentEncoding)) @@ -99,7 +105,10 @@ func Test_Compress_Deflate(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Set("Accept-Encoding", "deflate") - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") require.Equal(t, "deflate", resp.Header.Get(fiber.HeaderContentEncoding)) @@ -123,7 +132,10 @@ func Test_Compress_Brotli(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Set("Accept-Encoding", "br") - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") require.Equal(t, "br", resp.Header.Get(fiber.HeaderContentEncoding)) @@ -147,7 +159,10 @@ func Test_Compress_Zstd(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Set("Accept-Encoding", "zstd") - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") require.Equal(t, "zstd", resp.Header.Get(fiber.HeaderContentEncoding)) @@ -171,7 +186,10 @@ func Test_Compress_Disabled(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Set("Accept-Encoding", "br") - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") require.Equal(t, "", resp.Header.Get(fiber.HeaderContentEncoding)) diff --git a/middleware/idempotency/idempotency_test.go b/middleware/idempotency/idempotency_test.go index 91394ca26a..9cf66e7c9d 100644 --- a/middleware/idempotency/idempotency_test.go +++ b/middleware/idempotency/idempotency_test.go @@ -82,7 +82,10 @@ func Test_Idempotency(t *testing.T) { if idempotencyKey != "" { req.Header.Set("X-Idempotency-Key", idempotencyKey) } - resp, err := app.Test(req, 15*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 15*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) body, err := io.ReadAll(resp.Body) require.NoError(t, err) diff --git a/middleware/keyauth/keyauth_test.go b/middleware/keyauth/keyauth_test.go index 9da675fe8f..2bd52f7138 100644 --- a/middleware/keyauth/keyauth_test.go +++ b/middleware/keyauth/keyauth_test.go @@ -104,7 +104,10 @@ func Test_AuthSources(t *testing.T) { req.URL.Path = r } - res, err := app.Test(req, -1) + res, err := app.Test(req, fiber.TestConfig{ + Timeout: -1, + ErrOnTimeout: false, + }) require.NoError(t, err, test.description) @@ -209,7 +212,10 @@ func TestMultipleKeyLookup(t *testing.T) { q.Add("key", CorrectKey) req.URL.RawQuery = q.Encode() - res, err := app.Test(req, -1) + res, err := app.Test(req, fiber.TestConfig{ + Timeout: -1, + ErrOnTimeout: false, + }) require.NoError(t, err) @@ -226,7 +232,10 @@ func TestMultipleKeyLookup(t *testing.T) { // construct a second request without proper key req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/foo", nil) require.NoError(t, err) - res, err = app.Test(req, -1) + res, err = app.Test(req, fiber.TestConfig{ + Timeout: -1, + ErrOnTimeout: false, + }) require.NoError(t, err) errBody, err := io.ReadAll(res.Body) require.NoError(t, err) @@ -350,7 +359,10 @@ func Test_MultipleKeyAuth(t *testing.T) { req.Header.Set("key", test.APIKey) } - res, err := app.Test(req, -1) + res, err := app.Test(req, fiber.TestConfig{ + Timeout: -1, + ErrOnTimeout: false, + }) require.NoError(t, err, test.description) diff --git a/middleware/logger/logger_test.go b/middleware/logger/logger_test.go index 0bc06531c9..b6df6d1daf 100644 --- a/middleware/logger/logger_test.go +++ b/middleware/logger/logger_test.go @@ -300,7 +300,10 @@ 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), 3*time.Second) + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ + Timeout: 3*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode) @@ -342,7 +345,10 @@ func Test_Logger_WithLatency_DefaultFormat(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), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode) diff --git a/middleware/pprof/pprof_test.go b/middleware/pprof/pprof_test.go index 7a279d488d..5f26e95011 100644 --- a/middleware/pprof/pprof_test.go +++ b/middleware/pprof/pprof_test.go @@ -105,7 +105,10 @@ func Test_Pprof_Subs(t *testing.T) { if sub == "profile" { target += "?seconds=1" } - resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), 5*time.Second) + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), fiber.TestConfig{ + Timeout: 5*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) }) @@ -132,7 +135,10 @@ func Test_Pprof_Subs_WithPrefix(t *testing.T) { if sub == "profile" { target += "?seconds=1" } - resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), 5*time.Second) + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), fiber.TestConfig{ + Timeout: 5*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) }) diff --git a/middleware/proxy/proxy_test.go b/middleware/proxy/proxy_test.go index 713488a52b..153cb91fee 100644 --- a/middleware/proxy/proxy_test.go +++ b/middleware/proxy/proxy_test.go @@ -110,7 +110,10 @@ func Test_Proxy(t *testing.T) { return c.SendStatus(fiber.StatusTeapot) }) - resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2*time.Second) + resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) @@ -172,7 +175,10 @@ func Test_Proxy_Balancer_IPv6_Upstream(t *testing.T) { return c.SendStatus(fiber.StatusTeapot) }) - resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2*time.Second) + resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) @@ -195,7 +201,10 @@ func Test_Proxy_Balancer_IPv6_Upstream_With_DialDualStack(t *testing.T) { return c.SendStatus(fiber.StatusTeapot) }) - resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2*time.Second) + resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) @@ -221,7 +230,10 @@ func Test_Proxy_Balancer_IPv4_Upstream_With_DialDualStack(t *testing.T) { return c.SendStatus(fiber.StatusTeapot) }) - resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2*time.Second) + resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) @@ -399,7 +411,10 @@ func Test_Proxy_Timeout_Slow_Server(t *testing.T) { Timeout: 600 * time.Millisecond, })) - resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2*time.Second) + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode) @@ -423,7 +438,10 @@ func Test_Proxy_With_Timeout(t *testing.T) { Timeout: 100 * time.Millisecond, })) - resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2*time.Second) + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, fiber.StatusInternalServerError, resp.StatusCode) @@ -521,7 +539,10 @@ 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), 2*time.Second) + resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err1) _, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -559,7 +580,10 @@ 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), 2*time.Second) + resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err1) body, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -580,7 +604,10 @@ func Test_Proxy_DoTimeout_Timeout(t *testing.T) { return DoTimeout(c, "http://"+addr, time.Second) }) - resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 2*time.Second) + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) body, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -624,7 +651,10 @@ func Test_Proxy_DoDeadline_PastDeadline(t *testing.T) { return DoDeadline(c, "http://"+addr, time.Now().Add(2*time.Second)) }) - _, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 1*time.Second) + _, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ + Timeout: 1*time.Second, + ErrOnTimeout: true, + }) require.Equal(t, errors.New("test: timeout error after 1s"), err1) } @@ -717,7 +747,10 @@ func Test_ProxyBalancer_Custom_Client(t *testing.T) { return c.SendStatus(fiber.StatusTeapot) }) - resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2*time.Second) + resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ + Timeout: 2*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) diff --git a/middleware/static/static_test.go b/middleware/static/static_test.go index 4d736b0c43..0dff3bb039 100644 --- a/middleware/static/static_test.go +++ b/middleware/static/static_test.go @@ -738,7 +738,10 @@ func Test_Static_Compress(t *testing.T) { // request non-compressable file (less than 200 bytes), Content Lengh will remain the same req := httptest.NewRequest(fiber.MethodGet, "/css/style.css", nil) req.Header.Set("Accept-Encoding", algo) - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -748,7 +751,10 @@ func Test_Static_Compress(t *testing.T) { // request compressable file, ContentLenght will change req = httptest.NewRequest(fiber.MethodGet, "/index.html", nil) req.Header.Set("Accept-Encoding", algo) - resp, err = app.Test(req, 10*time.Second) + resp, err = app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -769,7 +775,10 @@ func Test_Static_Compress_WithoutEncoding(t *testing.T) { // request compressable file without encoding req := httptest.NewRequest(fiber.MethodGet, "/index.html", nil) - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -792,7 +801,10 @@ func Test_Static_Compress_WithoutEncoding(t *testing.T) { req = httptest.NewRequest(fiber.MethodGet, "/"+fileName, nil) req.Header.Set("Accept-Encoding", algo) - resp, err = app.Test(req, 10*time.Second) + resp, err = app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -833,7 +845,10 @@ func Test_Static_Compress_WithFileSuffixes(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/"+fileName, nil) req.Header.Set("Accept-Encoding", algo) - resp, err := app.Test(req, 10*time.Second) + resp, err := app.Test(req, fiber.TestConfig{ + Timeout: 10*time.Second, + ErrOnTimeout: true, + }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") From 073ec970aba422fff2e1ee5e25475cf020ada2c5 Mon Sep 17 00:00:00 2001 From: Giovanni Rivera Date: Wed, 2 Oct 2024 23:20:17 -0700 Subject: [PATCH 3/8] =?UTF-8?q?=F0=9F=93=9A=20Doc:=20Add=20more=20details?= =?UTF-8?q?=20about=20TestConfig=20in=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/api/app.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/api/app.md b/docs/api/app.md index 8b563b5c57..44330bbccb 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -566,6 +566,32 @@ if resp.StatusCode == fiber.StatusOK { } ``` +If not provided, TestConfig is set to the following defaults: + +```go title="Default TestConfig" +config := fiber.TestConfig{ + Timeout: time.Second(), + ErrOnTimeout: true, +} +``` + +:::caution + +This is **not** the same as supplying an empty `TestConfig{}` to +`app.Test(), but rather be the equivalent of supplying: + +```go title="Empty TestConfig" +cfg := fiber.TestConfig{ + Timeout: 0, + ErrOnTimeout: false, +} +``` + +This would make a Test that instantly times out, +which would always result in a "test: empty response" error. + +::: + ## Hooks Hooks is a method to return [hooks](./hooks.md) property. From 6c006a028f811f6e9b697405f18b8d8a82d75bdf Mon Sep 17 00:00:00 2001 From: Giovanni Rivera Date: Tue, 8 Oct 2024 22:12:12 +0000 Subject: [PATCH 4/8] =?UTF-8?q?=F0=9F=A9=B9=20Fix:=20Correct=20testConn=20?= =?UTF-8?q?tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixes Test_Utils_TestConn_Closed_Write - Fixes missing regular write test --- helpers_test.go | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/helpers_test.go b/helpers_test.go index 375274859f..e1dd1e50df 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -5,7 +5,6 @@ package fiber import ( - "errors" "strings" "testing" "time" @@ -515,21 +514,46 @@ func Test_Utils_TestConn_Deadline(t *testing.T) { require.NoError(t, conn.SetWriteDeadline(time.Time{})) } +func Test_Utils_TestConn_ReadWrite(t *testing.T) { + t.Parallel() + conn := &testConn{} + + // Verify read of request + _, err := conn.r.Write([]byte("Request")) + require.NoError(t, err) + + req := make([]byte, 7) + _, err = conn.Read(req) + require.NoError(t, err) + require.Equal(t, []byte("Request"), req) + + // Verify write of response + _, err = conn.Write([]byte("Response")) + require.NoError(t, err) + + res := make([]byte, 8) + _, err = conn.w.Read(res) + require.NoError(t, err) + require.Equal(t, []byte("Response"), res) +} + func Test_Utils_TestConn_Closed_Write(t *testing.T) { t.Parallel() conn := &testConn{} - _, err := conn.Write([]byte("Hello World")) + // Verify write of response + _, err := conn.Write([]byte("Response 1\n")) require.NoError(t, err) + // Close early, write should fail conn.Close() - _, err = conn.Write([]byte("This should fail")) - require.ErrorIs(t, err, errors.New("testConn is closed")) + _, err = conn.Write([]byte("Response 2\n")) + require.Error(t, err) - buffer := make([]byte, 12) - _, err = conn.Read(buffer) + res := make([]byte, 11) + _, err = conn.w.Read(res) require.NoError(t, err) - require.Equal(t, []byte("Hello World"), buffer) + require.Equal(t, []byte("Response 1\n"), res) } func Test_Utils_IsNoCache(t *testing.T) { From b07e05df7a6930702875c7e6610e935c3941e058 Mon Sep 17 00:00:00 2001 From: Giovanni Rivera Date: Tue, 8 Oct 2024 23:39:42 +0000 Subject: [PATCH 5/8] =?UTF-8?q?=F0=9F=8E=A8=20Style:=20Respect=20linter=20?= =?UTF-8?q?in=20Add=20App=20Test=20Config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.go | 10 +++++----- app_test.go | 10 +++++----- ctx_test.go | 2 +- helpers_test.go | 2 +- middleware/compress/compress_test.go | 12 ++++++------ middleware/idempotency/idempotency_test.go | 2 +- middleware/keyauth/keyauth_test.go | 8 ++++---- middleware/logger/logger_test.go | 4 ++-- middleware/pprof/pprof_test.go | 4 ++-- middleware/proxy/proxy_test.go | 22 +++++++++++----------- middleware/static/static_test.go | 10 +++++----- 11 files changed, 43 insertions(+), 43 deletions(-) diff --git a/app.go b/app.go index 82ba039a61..68f406246c 100644 --- a/app.go +++ b/app.go @@ -866,7 +866,7 @@ func (app *App) Hooks() *Hooks { } // TestConfig is a struct holding Test settings -type TestConfig struct { //nolint:govet // Aligning the struct fields is not necessary. betteralign:ignore +type TestConfig struct { // Sets a timeout duration for the test. // // Default: time.Second @@ -883,9 +883,9 @@ type TestConfig struct { //nolint:govet // Aligning the struct fields is not nec // Config is optional and defaults to a 1s error on timeout, // -1 timeout will disable it completely. func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, error) { - // Default config + // Default config cfg := TestConfig{ - Timeout: time.Second, + Timeout: time.Second, ErrOnTimeout: true, } @@ -935,7 +935,7 @@ func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, e select { case err = <-channel: case <-time.After(cfg.Timeout): - conn.Close() + conn.Close() //nolint:errcheck, revive // It is fine to ignore the error here if cfg.ErrOnTimeout { return nil, fmt.Errorf("test: timeout error after %s", cfg.Timeout) } @@ -956,7 +956,7 @@ func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, e // Convert raw http response to *http.Response res, err := http.ReadResponse(buffer, req) if err != nil { - if err == io.ErrUnexpectedEOF { + if errors.Is(err, io.ErrUnexpectedEOF) { return nil, fmt.Errorf("test: got empty response") } return nil, fmt.Errorf("failed to read response: %w", err) diff --git a/app_test.go b/app_test.go index 507fe999be..44034c1634 100644 --- a/app_test.go +++ b/app_test.go @@ -1125,7 +1125,7 @@ func Test_Test_Timeout(t *testing.T) { app.Get("/", testEmptyHandler) resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{ - Timeout: -1, + Timeout: -1, ErrOnTimeout: false, }) require.NoError(t, err, "app.Test(req)") @@ -1137,7 +1137,7 @@ func Test_Test_Timeout(t *testing.T) { }) _, err = app.Test(httptest.NewRequest(MethodGet, "/timeout", nil), TestConfig{ - Timeout: 20*time.Millisecond, + Timeout: 20 * time.Millisecond, ErrOnTimeout: true, }) require.Error(t, err, "app.Test(req)") @@ -1439,7 +1439,7 @@ func Test_App_Test_no_timeout_infinitely(t *testing.T) { req := httptest.NewRequest(MethodGet, "/", nil) _, err = app.Test(req, TestConfig{ - Timeout: -1, + Timeout: -1, ErrOnTimeout: true, }) }() @@ -1470,7 +1470,7 @@ func Test_App_Test_timeout(t *testing.T) { }) _, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{ - Timeout: 100*time.Millisecond, + Timeout: 100 * time.Millisecond, ErrOnTimeout: true, }) require.Equal(t, errors.New("test: timeout error after 100ms"), err) @@ -1486,7 +1486,7 @@ func Test_App_Test_timeout_empty_response(t *testing.T) { }) _, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{ - Timeout: 100*time.Millisecond, + Timeout: 100 * time.Millisecond, ErrOnTimeout: false, }) require.Equal(t, errors.New("test: got empty response"), err) diff --git a/ctx_test.go b/ctx_test.go index 5f0e7d023d..5f4ae20e35 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -3143,7 +3143,7 @@ func Test_Static_Compress(t *testing.T) { req := httptest.NewRequest(MethodGet, "/file", nil) req.Header.Set("Accept-Encoding", algo) resp, err := app.Test(req, TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) diff --git a/helpers_test.go b/helpers_test.go index e1dd1e50df..28a5df2ae7 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -546,7 +546,7 @@ func Test_Utils_TestConn_Closed_Write(t *testing.T) { require.NoError(t, err) // Close early, write should fail - conn.Close() + conn.Close() //nolint:errcheck, revive // It is fine to ignore the error here _, err = conn.Write([]byte("Response 2\n")) require.Error(t, err) diff --git a/middleware/compress/compress_test.go b/middleware/compress/compress_test.go index 5de1127d66..2e0aa08d1d 100644 --- a/middleware/compress/compress_test.go +++ b/middleware/compress/compress_test.go @@ -40,7 +40,7 @@ func Test_Compress_Gzip(t *testing.T) { req.Header.Set("Accept-Encoding", "gzip") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") @@ -76,7 +76,7 @@ func Test_Compress_Different_Level(t *testing.T) { req.Header.Set("Accept-Encoding", algo) resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") @@ -106,7 +106,7 @@ func Test_Compress_Deflate(t *testing.T) { req.Header.Set("Accept-Encoding", "deflate") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") @@ -133,7 +133,7 @@ func Test_Compress_Brotli(t *testing.T) { req.Header.Set("Accept-Encoding", "br") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") @@ -160,7 +160,7 @@ func Test_Compress_Zstd(t *testing.T) { req.Header.Set("Accept-Encoding", "zstd") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") @@ -187,7 +187,7 @@ func Test_Compress_Disabled(t *testing.T) { req.Header.Set("Accept-Encoding", "br") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") diff --git a/middleware/idempotency/idempotency_test.go b/middleware/idempotency/idempotency_test.go index 9cf66e7c9d..07ddd03eea 100644 --- a/middleware/idempotency/idempotency_test.go +++ b/middleware/idempotency/idempotency_test.go @@ -83,7 +83,7 @@ func Test_Idempotency(t *testing.T) { req.Header.Set("X-Idempotency-Key", idempotencyKey) } resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 15*time.Second, + Timeout: 15 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) diff --git a/middleware/keyauth/keyauth_test.go b/middleware/keyauth/keyauth_test.go index 2bd52f7138..b7acc9d4f4 100644 --- a/middleware/keyauth/keyauth_test.go +++ b/middleware/keyauth/keyauth_test.go @@ -105,7 +105,7 @@ func Test_AuthSources(t *testing.T) { } res, err := app.Test(req, fiber.TestConfig{ - Timeout: -1, + Timeout: -1, ErrOnTimeout: false, }) @@ -213,7 +213,7 @@ func TestMultipleKeyLookup(t *testing.T) { req.URL.RawQuery = q.Encode() res, err := app.Test(req, fiber.TestConfig{ - Timeout: -1, + Timeout: -1, ErrOnTimeout: false, }) @@ -233,7 +233,7 @@ func TestMultipleKeyLookup(t *testing.T) { req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/foo", nil) require.NoError(t, err) res, err = app.Test(req, fiber.TestConfig{ - Timeout: -1, + Timeout: -1, ErrOnTimeout: false, }) require.NoError(t, err) @@ -360,7 +360,7 @@ func Test_MultipleKeyAuth(t *testing.T) { } res, err := app.Test(req, fiber.TestConfig{ - Timeout: -1, + Timeout: -1, ErrOnTimeout: false, }) diff --git a/middleware/logger/logger_test.go b/middleware/logger/logger_test.go index b6df6d1daf..bfffcb11c6 100644 --- a/middleware/logger/logger_test.go +++ b/middleware/logger/logger_test.go @@ -301,7 +301,7 @@ func Test_Logger_WithLatency(t *testing.T) { // Create a new HTTP request to the test route resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 3*time.Second, + Timeout: 3 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) @@ -346,7 +346,7 @@ func Test_Logger_WithLatency_DefaultFormat(t *testing.T) { // Create a new HTTP request to the test route resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) diff --git a/middleware/pprof/pprof_test.go b/middleware/pprof/pprof_test.go index 5f26e95011..a80578a527 100644 --- a/middleware/pprof/pprof_test.go +++ b/middleware/pprof/pprof_test.go @@ -106,7 +106,7 @@ func Test_Pprof_Subs(t *testing.T) { target += "?seconds=1" } resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), fiber.TestConfig{ - Timeout: 5*time.Second, + Timeout: 5 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) @@ -136,7 +136,7 @@ func Test_Pprof_Subs_WithPrefix(t *testing.T) { target += "?seconds=1" } resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), fiber.TestConfig{ - Timeout: 5*time.Second, + Timeout: 5 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) diff --git a/middleware/proxy/proxy_test.go b/middleware/proxy/proxy_test.go index 153cb91fee..85632e3434 100644 --- a/middleware/proxy/proxy_test.go +++ b/middleware/proxy/proxy_test.go @@ -111,7 +111,7 @@ func Test_Proxy(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) @@ -176,7 +176,7 @@ func Test_Proxy_Balancer_IPv6_Upstream(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) @@ -202,7 +202,7 @@ func Test_Proxy_Balancer_IPv6_Upstream_With_DialDualStack(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) @@ -231,7 +231,7 @@ func Test_Proxy_Balancer_IPv4_Upstream_With_DialDualStack(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) @@ -412,7 +412,7 @@ func Test_Proxy_Timeout_Slow_Server(t *testing.T) { })) resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) @@ -439,7 +439,7 @@ func Test_Proxy_With_Timeout(t *testing.T) { })) resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) @@ -540,7 +540,7 @@ func Test_Proxy_DoRedirects_RestoreOriginalURL(t *testing.T) { }) resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err1) @@ -581,7 +581,7 @@ func Test_Proxy_DoTimeout_RestoreOriginalURL(t *testing.T) { }) resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err1) @@ -605,7 +605,7 @@ func Test_Proxy_DoTimeout_Timeout(t *testing.T) { }) resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) @@ -652,7 +652,7 @@ func Test_Proxy_DoDeadline_PastDeadline(t *testing.T) { }) _, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 1*time.Second, + Timeout: 1 * time.Second, ErrOnTimeout: true, }) require.Equal(t, errors.New("test: timeout error after 1s"), err1) @@ -748,7 +748,7 @@ func Test_ProxyBalancer_Custom_Client(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2*time.Second, + Timeout: 2 * time.Second, ErrOnTimeout: true, }) require.NoError(t, err) diff --git a/middleware/static/static_test.go b/middleware/static/static_test.go index 0dff3bb039..7117c7dafa 100644 --- a/middleware/static/static_test.go +++ b/middleware/static/static_test.go @@ -739,7 +739,7 @@ func Test_Static_Compress(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/css/style.css", nil) req.Header.Set("Accept-Encoding", algo) resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) @@ -752,7 +752,7 @@ func Test_Static_Compress(t *testing.T) { req = httptest.NewRequest(fiber.MethodGet, "/index.html", nil) req.Header.Set("Accept-Encoding", algo) resp, err = app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) @@ -776,7 +776,7 @@ func Test_Static_Compress_WithoutEncoding(t *testing.T) { // request compressable file without encoding req := httptest.NewRequest(fiber.MethodGet, "/index.html", nil) resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) @@ -802,7 +802,7 @@ func Test_Static_Compress_WithoutEncoding(t *testing.T) { req = httptest.NewRequest(fiber.MethodGet, "/"+fileName, nil) req.Header.Set("Accept-Encoding", algo) resp, err = app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) @@ -846,7 +846,7 @@ func Test_Static_Compress_WithFileSuffixes(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/"+fileName, nil) req.Header.Set("Accept-Encoding", algo) resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10*time.Second, + Timeout: 10 * time.Second, ErrOnTimeout: true, }) From 4a97d7b6be4a72b15e9ce12fa7cf9a779b499cd4 Mon Sep 17 00:00:00 2001 From: Giovanni Rivera Date: Wed, 9 Oct 2024 16:11:47 -0700 Subject: [PATCH 6/8] =?UTF-8?q?=F0=9F=8E=A8=20Styles:=20Update=20app.go=20?= =?UTF-8?q?to=20respect=20linter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index 68f406246c..c0f82e3603 100644 --- a/app.go +++ b/app.go @@ -957,7 +957,7 @@ func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, e res, err := http.ReadResponse(buffer, req) if err != nil { if errors.Is(err, io.ErrUnexpectedEOF) { - return nil, fmt.Errorf("test: got empty response") + return nil, errors.New("test: got empty response") } return nil, fmt.Errorf("failed to read response: %w", err) } From 37761841e018f1bad165660bf5ca7382d501fba7 Mon Sep 17 00:00:00 2001 From: Giovanni Rivera Date: Tue, 22 Oct 2024 22:14:55 -0700 Subject: [PATCH 7/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20Rename=20T?= =?UTF-8?q?estConfig's=20ErrOnTimeout=20to=20FailOnTimeout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename TestConfig.ErrOnTimeout to TestConfig.FailOnTimeout - Update documentation to use changed name - Also fix stale documentation about passing Timeout as a single argument --- app.go | 18 ++++----- app_test.go | 20 +++++----- ctx_test.go | 4 +- docs/api/app.md | 6 +-- middleware/compress/compress_test.go | 24 ++++++------ middleware/idempotency/idempotency_test.go | 4 +- middleware/keyauth/keyauth_test.go | 16 ++++---- middleware/logger/logger_test.go | 8 ++-- middleware/pprof/pprof_test.go | 8 ++-- middleware/proxy/proxy_test.go | 44 +++++++++++----------- middleware/static/static_test.go | 20 +++++----- 11 files changed, 86 insertions(+), 86 deletions(-) diff --git a/app.go b/app.go index c0f82e3603..1ca61afeae 100644 --- a/app.go +++ b/app.go @@ -867,16 +867,16 @@ func (app *App) Hooks() *Hooks { // TestConfig is a struct holding Test settings type TestConfig struct { - // Sets a timeout duration for the test. - // + // Timeout defines the maximum duration a + // test can run before timing out. // Default: time.Second Timeout time.Duration - // When set to true, the test will discard the - // current http response and give a timeout error. - // + // FailOnTimeout specified whether the test + // should return a timeout error if the HTTP response + // exceeds the Timeout duration. // Default: true - ErrOnTimeout bool + FailOnTimeout bool } // Test is used for internal debugging by passing a *http.Request. @@ -885,8 +885,8 @@ type TestConfig struct { func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, error) { // Default config cfg := TestConfig{ - Timeout: time.Second, - ErrOnTimeout: true, + Timeout: time.Second, + FailOnTimeout: true, } // Override config if provided @@ -936,7 +936,7 @@ func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, e case err = <-channel: case <-time.After(cfg.Timeout): conn.Close() //nolint:errcheck, revive // It is fine to ignore the error here - if cfg.ErrOnTimeout { + if cfg.FailOnTimeout { return nil, fmt.Errorf("test: timeout error after %s", cfg.Timeout) } } diff --git a/app_test.go b/app_test.go index 44034c1634..db790430d0 100644 --- a/app_test.go +++ b/app_test.go @@ -1125,8 +1125,8 @@ func Test_Test_Timeout(t *testing.T) { app.Get("/", testEmptyHandler) resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{ - Timeout: -1, - ErrOnTimeout: false, + Timeout: -1, + FailOnTimeout: false, }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -1137,8 +1137,8 @@ func Test_Test_Timeout(t *testing.T) { }) _, err = app.Test(httptest.NewRequest(MethodGet, "/timeout", nil), TestConfig{ - Timeout: 20 * time.Millisecond, - ErrOnTimeout: true, + Timeout: 20 * time.Millisecond, + FailOnTimeout: true, }) require.Error(t, err, "app.Test(req)") } @@ -1439,8 +1439,8 @@ func Test_App_Test_no_timeout_infinitely(t *testing.T) { req := httptest.NewRequest(MethodGet, "/", nil) _, err = app.Test(req, TestConfig{ - Timeout: -1, - ErrOnTimeout: true, + Timeout: -1, + FailOnTimeout: true, }) }() @@ -1470,8 +1470,8 @@ func Test_App_Test_timeout(t *testing.T) { }) _, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{ - Timeout: 100 * time.Millisecond, - ErrOnTimeout: true, + Timeout: 100 * time.Millisecond, + FailOnTimeout: true, }) require.Equal(t, errors.New("test: timeout error after 100ms"), err) } @@ -1486,8 +1486,8 @@ func Test_App_Test_timeout_empty_response(t *testing.T) { }) _, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{ - Timeout: 100 * time.Millisecond, - ErrOnTimeout: false, + Timeout: 100 * time.Millisecond, + FailOnTimeout: false, }) require.Equal(t, errors.New("test: got empty response"), err) } diff --git a/ctx_test.go b/ctx_test.go index 5f4ae20e35..60bb1e547b 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -3143,8 +3143,8 @@ func Test_Static_Compress(t *testing.T) { req := httptest.NewRequest(MethodGet, "/file", nil) req.Header.Set("Accept-Encoding", algo) resp, err := app.Test(req, TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") diff --git a/docs/api/app.md b/docs/api/app.md index 44330bbccb..822d997988 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -537,7 +537,7 @@ func (app *App) SetTLSHandler(tlsHandler *TLSHandler) ## Test -Testing your application is done with the **Test** method. Use this method for creating `_test.go` files or when you need to debug your routing logic. The default timeout is `1s` if you want to disable a timeout altogether, pass `-1` as a second argument. +Testing your application is done with the **Test** method. Use this method for creating `_test.go` files or when you need to debug your routing logic. The default timeout is `1s`. If you want to disable a timeout altogether, pass a `TestConfig` struct with `Timeout: -1`. ```go title="Signature" func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, error) @@ -571,7 +571,7 @@ If not provided, TestConfig is set to the following defaults: ```go title="Default TestConfig" config := fiber.TestConfig{ Timeout: time.Second(), - ErrOnTimeout: true, + FailOnTimeout: true, } ``` @@ -583,7 +583,7 @@ This is **not** the same as supplying an empty `TestConfig{}` to ```go title="Empty TestConfig" cfg := fiber.TestConfig{ Timeout: 0, - ErrOnTimeout: false, + FailOnTimeout: false, } ``` diff --git a/middleware/compress/compress_test.go b/middleware/compress/compress_test.go index 2e0aa08d1d..4e46e3edec 100644 --- a/middleware/compress/compress_test.go +++ b/middleware/compress/compress_test.go @@ -40,8 +40,8 @@ func Test_Compress_Gzip(t *testing.T) { req.Header.Set("Accept-Encoding", "gzip") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -76,8 +76,8 @@ func Test_Compress_Different_Level(t *testing.T) { req.Header.Set("Accept-Encoding", algo) resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -106,8 +106,8 @@ func Test_Compress_Deflate(t *testing.T) { req.Header.Set("Accept-Encoding", "deflate") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -133,8 +133,8 @@ func Test_Compress_Brotli(t *testing.T) { req.Header.Set("Accept-Encoding", "br") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -160,8 +160,8 @@ func Test_Compress_Zstd(t *testing.T) { req.Header.Set("Accept-Encoding", "zstd") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") @@ -187,8 +187,8 @@ func Test_Compress_Disabled(t *testing.T) { req.Header.Set("Accept-Encoding", "br") resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") require.Equal(t, 200, resp.StatusCode, "Status code") diff --git a/middleware/idempotency/idempotency_test.go b/middleware/idempotency/idempotency_test.go index 07ddd03eea..56b10d9c03 100644 --- a/middleware/idempotency/idempotency_test.go +++ b/middleware/idempotency/idempotency_test.go @@ -83,8 +83,8 @@ func Test_Idempotency(t *testing.T) { req.Header.Set("X-Idempotency-Key", idempotencyKey) } resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 15 * time.Second, - ErrOnTimeout: true, + Timeout: 15 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) body, err := io.ReadAll(resp.Body) diff --git a/middleware/keyauth/keyauth_test.go b/middleware/keyauth/keyauth_test.go index b7acc9d4f4..60d71cafa1 100644 --- a/middleware/keyauth/keyauth_test.go +++ b/middleware/keyauth/keyauth_test.go @@ -105,8 +105,8 @@ func Test_AuthSources(t *testing.T) { } res, err := app.Test(req, fiber.TestConfig{ - Timeout: -1, - ErrOnTimeout: false, + Timeout: -1, + FailOnTimeout: false, }) require.NoError(t, err, test.description) @@ -213,8 +213,8 @@ func TestMultipleKeyLookup(t *testing.T) { req.URL.RawQuery = q.Encode() res, err := app.Test(req, fiber.TestConfig{ - Timeout: -1, - ErrOnTimeout: false, + Timeout: -1, + FailOnTimeout: false, }) require.NoError(t, err) @@ -233,8 +233,8 @@ func TestMultipleKeyLookup(t *testing.T) { req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/foo", nil) require.NoError(t, err) res, err = app.Test(req, fiber.TestConfig{ - Timeout: -1, - ErrOnTimeout: false, + Timeout: -1, + FailOnTimeout: false, }) require.NoError(t, err) errBody, err := io.ReadAll(res.Body) @@ -360,8 +360,8 @@ func Test_MultipleKeyAuth(t *testing.T) { } res, err := app.Test(req, fiber.TestConfig{ - Timeout: -1, - ErrOnTimeout: false, + Timeout: -1, + FailOnTimeout: false, }) require.NoError(t, err, test.description) diff --git a/middleware/logger/logger_test.go b/middleware/logger/logger_test.go index bfffcb11c6..570b046ae0 100644 --- a/middleware/logger/logger_test.go +++ b/middleware/logger/logger_test.go @@ -301,8 +301,8 @@ func Test_Logger_WithLatency(t *testing.T) { // Create a new HTTP request to the test route resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 3 * time.Second, - ErrOnTimeout: true, + Timeout: 3 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode) @@ -346,8 +346,8 @@ func Test_Logger_WithLatency_DefaultFormat(t *testing.T) { // Create a new HTTP request to the test route resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode) diff --git a/middleware/pprof/pprof_test.go b/middleware/pprof/pprof_test.go index a80578a527..e163804a6b 100644 --- a/middleware/pprof/pprof_test.go +++ b/middleware/pprof/pprof_test.go @@ -106,8 +106,8 @@ func Test_Pprof_Subs(t *testing.T) { target += "?seconds=1" } resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), fiber.TestConfig{ - Timeout: 5 * time.Second, - ErrOnTimeout: true, + Timeout: 5 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) @@ -136,8 +136,8 @@ func Test_Pprof_Subs_WithPrefix(t *testing.T) { target += "?seconds=1" } resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), fiber.TestConfig{ - Timeout: 5 * time.Second, - ErrOnTimeout: true, + Timeout: 5 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) diff --git a/middleware/proxy/proxy_test.go b/middleware/proxy/proxy_test.go index 85632e3434..de2b7701cf 100644 --- a/middleware/proxy/proxy_test.go +++ b/middleware/proxy/proxy_test.go @@ -111,8 +111,8 @@ func Test_Proxy(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) @@ -176,8 +176,8 @@ func Test_Proxy_Balancer_IPv6_Upstream(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) @@ -202,8 +202,8 @@ func Test_Proxy_Balancer_IPv6_Upstream_With_DialDualStack(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) @@ -231,8 +231,8 @@ func Test_Proxy_Balancer_IPv4_Upstream_With_DialDualStack(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) @@ -412,8 +412,8 @@ func Test_Proxy_Timeout_Slow_Server(t *testing.T) { })) resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, fiber.StatusOK, resp.StatusCode) @@ -439,8 +439,8 @@ func Test_Proxy_With_Timeout(t *testing.T) { })) resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, fiber.StatusInternalServerError, resp.StatusCode) @@ -540,8 +540,8 @@ func Test_Proxy_DoRedirects_RestoreOriginalURL(t *testing.T) { }) resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err1) _, err := io.ReadAll(resp.Body) @@ -581,8 +581,8 @@ func Test_Proxy_DoTimeout_RestoreOriginalURL(t *testing.T) { }) resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err1) body, err := io.ReadAll(resp.Body) @@ -605,8 +605,8 @@ func Test_Proxy_DoTimeout_Timeout(t *testing.T) { }) resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) body, err := io.ReadAll(resp.Body) @@ -652,8 +652,8 @@ func Test_Proxy_DoDeadline_PastDeadline(t *testing.T) { }) _, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{ - Timeout: 1 * time.Second, - ErrOnTimeout: true, + Timeout: 1 * time.Second, + FailOnTimeout: true, }) require.Equal(t, errors.New("test: timeout error after 1s"), err1) } @@ -748,8 +748,8 @@ func Test_ProxyBalancer_Custom_Client(t *testing.T) { }) resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), fiber.TestConfig{ - Timeout: 2 * time.Second, - ErrOnTimeout: true, + Timeout: 2 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err) require.Equal(t, fiber.StatusTeapot, resp.StatusCode) diff --git a/middleware/static/static_test.go b/middleware/static/static_test.go index 7117c7dafa..231332ef77 100644 --- a/middleware/static/static_test.go +++ b/middleware/static/static_test.go @@ -739,8 +739,8 @@ func Test_Static_Compress(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/css/style.css", nil) req.Header.Set("Accept-Encoding", algo) resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") @@ -752,8 +752,8 @@ func Test_Static_Compress(t *testing.T) { req = httptest.NewRequest(fiber.MethodGet, "/index.html", nil) req.Header.Set("Accept-Encoding", algo) resp, err = app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") @@ -776,8 +776,8 @@ func Test_Static_Compress_WithoutEncoding(t *testing.T) { // request compressable file without encoding req := httptest.NewRequest(fiber.MethodGet, "/index.html", nil) resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") @@ -802,8 +802,8 @@ func Test_Static_Compress_WithoutEncoding(t *testing.T) { req = httptest.NewRequest(fiber.MethodGet, "/"+fileName, nil) req.Header.Set("Accept-Encoding", algo) resp, err = app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") @@ -846,8 +846,8 @@ func Test_Static_Compress_WithFileSuffixes(t *testing.T) { req := httptest.NewRequest(fiber.MethodGet, "/"+fileName, nil) req.Header.Set("Accept-Encoding", algo) resp, err := app.Test(req, fiber.TestConfig{ - Timeout: 10 * time.Second, - ErrOnTimeout: true, + Timeout: 10 * time.Second, + FailOnTimeout: true, }) require.NoError(t, err, "app.Test(req)") From 78e32a7dbd88f013d150c713ab631c10d8521deb Mon Sep 17 00:00:00 2001 From: Giovanni Rivera Date: Tue, 22 Oct 2024 22:21:32 -0700 Subject: [PATCH 8/8] =?UTF-8?q?=F0=9F=A9=B9=20Fix:=20Fix=20typo=20in=20Tes?= =?UTF-8?q?tConfig=20struct=20comment=20in=20app.go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index 1ca61afeae..a8306bbc34 100644 --- a/app.go +++ b/app.go @@ -872,7 +872,7 @@ type TestConfig struct { // Default: time.Second Timeout time.Duration - // FailOnTimeout specified whether the test + // FailOnTimeout specifies whether the test // should return a timeout error if the HTTP response // exceeds the Timeout duration. // Default: true