Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9647ec8

Browse files
committedOct 2, 2024
Add TestConfig to app.Test()
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 gofiber#3149
1 parent 845c539 commit 9647ec8

File tree

9 files changed

+133
-30
lines changed

9 files changed

+133
-30
lines changed
 

‎app.go

+36-9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"encoding/xml"
1515
"errors"
1616
"fmt"
17+
"io"
1718
"net"
1819
"net/http"
1920
"net/http/httputil"
@@ -864,13 +865,33 @@ func (app *App) Hooks() *Hooks {
864865
return app.hooks
865866
}
866867

868+
// TestConfig is a struct holding Test settings
869+
type TestConfig struct { //nolint:govet // Aligning the struct fields is not necessary. betteralign:ignore
870+
// Sets a timeout duration for the test.
871+
//
872+
// Default: time.Second
873+
Timeout time.Duration
874+
875+
// When set to true, the test will discard the
876+
// current http response and give a timeout error.
877+
//
878+
// Default: true
879+
ErrOnTimeout bool
880+
}
881+
867882
// Test is used for internal debugging by passing a *http.Request.
868-
// Timeout is optional and defaults to 1s, -1 will disable it completely.
869-
func (app *App) Test(req *http.Request, timeout ...time.Duration) (*http.Response, error) {
870-
// Set timeout
871-
to := 1 * time.Second
872-
if len(timeout) > 0 {
873-
to = timeout[0]
883+
// Config is optional and defaults to a 1s error on timeout,
884+
// -1 timeout will disable it completely.
885+
func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, error) {
886+
// Default config
887+
cfg := TestConfig{
888+
Timeout: time.Second,
889+
ErrOnTimeout: true,
890+
}
891+
892+
// Override config if provided
893+
if len(config) > 0 {
894+
cfg = config[0]
874895
}
875896

876897
// Add Content-Length if not provided with body
@@ -909,12 +930,15 @@ func (app *App) Test(req *http.Request, timeout ...time.Duration) (*http.Respons
909930
}()
910931

911932
// Wait for callback
912-
if to >= 0 {
933+
if cfg.Timeout >= 0 {
913934
// With timeout
914935
select {
915936
case err = <-channel:
916-
case <-time.After(to):
917-
return nil, fmt.Errorf("test: timeout error after %s", to)
937+
case <-time.After(cfg.Timeout):
938+
conn.Close()
939+
if cfg.ErrOnTimeout {
940+
return nil, fmt.Errorf("test: timeout error after %s", cfg.Timeout)
941+
}
918942
}
919943
} else {
920944
// Without timeout
@@ -932,6 +956,9 @@ func (app *App) Test(req *http.Request, timeout ...time.Duration) (*http.Respons
932956
// Convert raw http response to *http.Response
933957
res, err := http.ReadResponse(buffer, req)
934958
if err != nil {
959+
if err == io.ErrUnexpectedEOF {
960+
return nil, fmt.Errorf("test: got empty response")
961+
}
935962
return nil, fmt.Errorf("failed to read response: %w", err)
936963
}
937964

‎app_test.go

+32-4
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,10 @@ func Test_Test_Timeout(t *testing.T) {
11241124

11251125
app.Get("/", testEmptyHandler)
11261126

1127-
resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), -1)
1127+
resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{
1128+
Timeout: -1,
1129+
ErrOnTimeout: false,
1130+
})
11281131
require.NoError(t, err, "app.Test(req)")
11291132
require.Equal(t, 200, resp.StatusCode, "Status code")
11301133

@@ -1133,7 +1136,10 @@ func Test_Test_Timeout(t *testing.T) {
11331136
return nil
11341137
})
11351138

1136-
_, err = app.Test(httptest.NewRequest(MethodGet, "/timeout", nil), 20*time.Millisecond)
1139+
_, err = app.Test(httptest.NewRequest(MethodGet, "/timeout", nil), TestConfig{
1140+
Timeout: 20*time.Millisecond,
1141+
ErrOnTimeout: true,
1142+
})
11371143
require.Error(t, err, "app.Test(req)")
11381144
}
11391145

@@ -1432,7 +1438,10 @@ func Test_App_Test_no_timeout_infinitely(t *testing.T) {
14321438
})
14331439

14341440
req := httptest.NewRequest(MethodGet, "/", nil)
1435-
_, err = app.Test(req, -1)
1441+
_, err = app.Test(req, TestConfig{
1442+
Timeout: -1,
1443+
ErrOnTimeout: true,
1444+
})
14361445
}()
14371446

14381447
tk := time.NewTimer(5 * time.Second)
@@ -1460,10 +1469,29 @@ func Test_App_Test_timeout(t *testing.T) {
14601469
return nil
14611470
})
14621471

1463-
_, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), 100*time.Millisecond)
1472+
_, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{
1473+
Timeout: 100*time.Millisecond,
1474+
ErrOnTimeout: true,
1475+
})
14641476
require.Equal(t, errors.New("test: timeout error after 100ms"), err)
14651477
}
14661478

1479+
func Test_App_Test_timeout_empty_response(t *testing.T) {
1480+
t.Parallel()
1481+
1482+
app := New()
1483+
app.Get("/", func(_ Ctx) error {
1484+
time.Sleep(1 * time.Second)
1485+
return nil
1486+
})
1487+
1488+
_, err := app.Test(httptest.NewRequest(MethodGet, "/", nil), TestConfig{
1489+
Timeout: 100*time.Millisecond,
1490+
ErrOnTimeout: false,
1491+
})
1492+
require.Equal(t, errors.New("test: got empty response"), err)
1493+
}
1494+
14671495
func Test_App_SetTLSHandler(t *testing.T) {
14681496
t.Parallel()
14691497
tlsHandler := &TLSHandler{clientHelloInfo: &tls.ClientHelloInfo{

‎ctx_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -3142,7 +3142,10 @@ func Test_Static_Compress(t *testing.T) {
31423142

31433143
req := httptest.NewRequest(MethodGet, "/file", nil)
31443144
req.Header.Set("Accept-Encoding", algo)
3145-
resp, err := app.Test(req, 10*time.Second)
3145+
resp, err := app.Test(req, TestConfig{
3146+
Timeout: 10*time.Second,
3147+
ErrOnTimeout: true,
3148+
})
31463149

31473150
require.NoError(t, err, "app.Test(req)")
31483151
require.Equal(t, 200, resp.StatusCode, "Status code")

‎docs/api/app.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ func (app *App) SetTLSHandler(tlsHandler *TLSHandler)
540540
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.
541541

542542
```go title="Signature"
543-
func (app *App) Test(req *http.Request, msTimeout ...int) (*http.Response, error)
543+
func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, error)
544544
```
545545

546546
```go title="Examples"

‎middleware/compress/compress_test.go

+24-6
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ func Test_Compress_Gzip(t *testing.T) {
3939
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
4040
req.Header.Set("Accept-Encoding", "gzip")
4141

42-
resp, err := app.Test(req, 10*time.Second)
42+
resp, err := app.Test(req, fiber.TestConfig{
43+
Timeout: 10*time.Second,
44+
ErrOnTimeout: true,
45+
})
4346
require.NoError(t, err, "app.Test(req)")
4447
require.Equal(t, 200, resp.StatusCode, "Status code")
4548
require.Equal(t, "gzip", resp.Header.Get(fiber.HeaderContentEncoding))
@@ -72,7 +75,10 @@ func Test_Compress_Different_Level(t *testing.T) {
7275
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
7376
req.Header.Set("Accept-Encoding", algo)
7477

75-
resp, err := app.Test(req, 10*time.Second)
78+
resp, err := app.Test(req, fiber.TestConfig{
79+
Timeout: 10*time.Second,
80+
ErrOnTimeout: true,
81+
})
7682
require.NoError(t, err, "app.Test(req)")
7783
require.Equal(t, 200, resp.StatusCode, "Status code")
7884
require.Equal(t, algo, resp.Header.Get(fiber.HeaderContentEncoding))
@@ -99,7 +105,10 @@ func Test_Compress_Deflate(t *testing.T) {
99105
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
100106
req.Header.Set("Accept-Encoding", "deflate")
101107

102-
resp, err := app.Test(req, 10*time.Second)
108+
resp, err := app.Test(req, fiber.TestConfig{
109+
Timeout: 10*time.Second,
110+
ErrOnTimeout: true,
111+
})
103112
require.NoError(t, err, "app.Test(req)")
104113
require.Equal(t, 200, resp.StatusCode, "Status code")
105114
require.Equal(t, "deflate", resp.Header.Get(fiber.HeaderContentEncoding))
@@ -123,7 +132,10 @@ func Test_Compress_Brotli(t *testing.T) {
123132
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
124133
req.Header.Set("Accept-Encoding", "br")
125134

126-
resp, err := app.Test(req, 10*time.Second)
135+
resp, err := app.Test(req, fiber.TestConfig{
136+
Timeout: 10*time.Second,
137+
ErrOnTimeout: true,
138+
})
127139
require.NoError(t, err, "app.Test(req)")
128140
require.Equal(t, 200, resp.StatusCode, "Status code")
129141
require.Equal(t, "br", resp.Header.Get(fiber.HeaderContentEncoding))
@@ -147,7 +159,10 @@ func Test_Compress_Zstd(t *testing.T) {
147159
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
148160
req.Header.Set("Accept-Encoding", "zstd")
149161

150-
resp, err := app.Test(req, 10*time.Second)
162+
resp, err := app.Test(req, fiber.TestConfig{
163+
Timeout: 10*time.Second,
164+
ErrOnTimeout: true,
165+
})
151166
require.NoError(t, err, "app.Test(req)")
152167
require.Equal(t, 200, resp.StatusCode, "Status code")
153168
require.Equal(t, "zstd", resp.Header.Get(fiber.HeaderContentEncoding))
@@ -171,7 +186,10 @@ func Test_Compress_Disabled(t *testing.T) {
171186
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
172187
req.Header.Set("Accept-Encoding", "br")
173188

174-
resp, err := app.Test(req, 10*time.Second)
189+
resp, err := app.Test(req, fiber.TestConfig{
190+
Timeout: 10*time.Second,
191+
ErrOnTimeout: true,
192+
})
175193
require.NoError(t, err, "app.Test(req)")
176194
require.Equal(t, 200, resp.StatusCode, "Status code")
177195
require.Equal(t, "", resp.Header.Get(fiber.HeaderContentEncoding))

‎middleware/idempotency/idempotency_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ func Test_Idempotency(t *testing.T) {
8282
if idempotencyKey != "" {
8383
req.Header.Set("X-Idempotency-Key", idempotencyKey)
8484
}
85-
resp, err := app.Test(req, 15*time.Second)
85+
resp, err := app.Test(req, fiber.TestConfig{
86+
Timeout: 15*time.Second,
87+
ErrOnTimeout: true,
88+
})
8689
require.NoError(t, err)
8790
body, err := io.ReadAll(resp.Body)
8891
require.NoError(t, err)

‎middleware/keyauth/keyauth_test.go

+16-4
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ func Test_AuthSources(t *testing.T) {
104104
req.URL.Path = r
105105
}
106106

107-
res, err := app.Test(req, -1)
107+
res, err := app.Test(req, fiber.TestConfig{
108+
Timeout: -1,
109+
ErrOnTimeout: false,
110+
})
108111

109112
require.NoError(t, err, test.description)
110113

@@ -209,7 +212,10 @@ func TestMultipleKeyLookup(t *testing.T) {
209212
q.Add("key", CorrectKey)
210213
req.URL.RawQuery = q.Encode()
211214

212-
res, err := app.Test(req, -1)
215+
res, err := app.Test(req, fiber.TestConfig{
216+
Timeout: -1,
217+
ErrOnTimeout: false,
218+
})
213219

214220
require.NoError(t, err)
215221

@@ -226,7 +232,10 @@ func TestMultipleKeyLookup(t *testing.T) {
226232
// construct a second request without proper key
227233
req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/foo", nil)
228234
require.NoError(t, err)
229-
res, err = app.Test(req, -1)
235+
res, err = app.Test(req, fiber.TestConfig{
236+
Timeout: -1,
237+
ErrOnTimeout: false,
238+
})
230239
require.NoError(t, err)
231240
errBody, err := io.ReadAll(res.Body)
232241
require.NoError(t, err)
@@ -350,7 +359,10 @@ func Test_MultipleKeyAuth(t *testing.T) {
350359
req.Header.Set("key", test.APIKey)
351360
}
352361

353-
res, err := app.Test(req, -1)
362+
res, err := app.Test(req, fiber.TestConfig{
363+
Timeout: -1,
364+
ErrOnTimeout: false,
365+
})
354366

355367
require.NoError(t, err, test.description)
356368

‎middleware/logger/logger_test.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,10 @@ func Test_Logger_WithLatency(t *testing.T) {
300300
sleepDuration = 1 * tu.div
301301

302302
// Create a new HTTP request to the test route
303-
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 3*time.Second)
303+
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{
304+
Timeout: 3*time.Second,
305+
ErrOnTimeout: true,
306+
})
304307
require.NoError(t, err)
305308
require.Equal(t, fiber.StatusOK, resp.StatusCode)
306309

@@ -342,7 +345,10 @@ func Test_Logger_WithLatency_DefaultFormat(t *testing.T) {
342345
sleepDuration = 1 * tu.div
343346

344347
// Create a new HTTP request to the test route
345-
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), 2*time.Second)
348+
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{
349+
Timeout: 2*time.Second,
350+
ErrOnTimeout: true,
351+
})
346352
require.NoError(t, err)
347353
require.Equal(t, fiber.StatusOK, resp.StatusCode)
348354

‎middleware/pprof/pprof_test.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ func Test_Pprof_Subs(t *testing.T) {
105105
if sub == "profile" {
106106
target += "?seconds=1"
107107
}
108-
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), 5*time.Second)
108+
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), fiber.TestConfig{
109+
Timeout: 5*time.Second,
110+
ErrOnTimeout: true,
111+
})
109112
require.NoError(t, err)
110113
require.Equal(t, 200, resp.StatusCode)
111114
})
@@ -132,7 +135,10 @@ func Test_Pprof_Subs_WithPrefix(t *testing.T) {
132135
if sub == "profile" {
133136
target += "?seconds=1"
134137
}
135-
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), 5*time.Second)
138+
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, target, nil), fiber.TestConfig{
139+
Timeout: 5*time.Second,
140+
ErrOnTimeout: true,
141+
})
136142
require.NoError(t, err)
137143
require.Equal(t, 200, resp.StatusCode)
138144
})

0 commit comments

Comments
 (0)
Please sign in to comment.