Skip to content

Commit d5f8837

Browse files
authored
Timeout mw: rework how test waits for timeout. Using sleep as delay i… (#2187)
* Timeout mw: rework how test waits for timeout. Using sleep as delay is problematic when CI worker is slower than usual.
1 parent 28797c7 commit d5f8837

File tree

1 file changed

+28
-21
lines changed

1 file changed

+28
-21
lines changed

middleware/timeout_test.go

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package middleware
22

33
import (
44
"bytes"
5+
"context"
56
"errors"
67
"fmt"
78
"io/ioutil"
@@ -328,12 +329,13 @@ func TestTimeoutCanHandleContextDeadlineOnNextHandler(t *testing.T) {
328329
func TestTimeoutWithFullEchoStack(t *testing.T) {
329330
// test timeout with full http server stack running, do see what http.Server.ErrorLog contains
330331
var testCases = []struct {
331-
name string
332-
whenPath string
333-
expectStatusCode int
334-
expectResponse string
335-
expectLogContains []string
336-
expectLogNotContains []string
332+
name string
333+
whenPath string
334+
whenForceHandlerTimeout bool
335+
expectStatusCode int
336+
expectResponse string
337+
expectLogContains []string
338+
expectLogNotContains []string
337339
}{
338340
{
339341
name: "404 - write response in global error handler",
@@ -352,14 +354,15 @@ func TestTimeoutWithFullEchoStack(t *testing.T) {
352354
expectLogContains: []string{`"status":418,"error":"",`},
353355
},
354356
{
355-
name: "503 - handler timeouts, write response in timeout middleware",
356-
whenPath: "/?delay=50ms",
357-
expectResponse: "<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>",
358-
expectStatusCode: http.StatusServiceUnavailable,
357+
name: "503 - handler timeouts, write response in timeout middleware",
358+
whenForceHandlerTimeout: true,
359+
whenPath: "/",
360+
expectResponse: "<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>",
361+
expectStatusCode: http.StatusServiceUnavailable,
359362
expectLogNotContains: []string{
360363
"echo:http: superfluous response.WriteHeader call from",
361-
"{", // means that logger was not called.
362364
},
365+
expectLogContains: []string{"http: Handler timeout"},
363366
},
364367
}
365368

@@ -371,21 +374,18 @@ func TestTimeoutWithFullEchoStack(t *testing.T) {
371374
e.Logger.SetOutput(buf)
372375

373376
// NOTE: timeout middleware is first as it changes Response.Writer and causes data race for logger middleware if it is not first
374-
// FIXME: I have no idea how to fix this without adding mutexes.
375377
e.Use(TimeoutWithConfig(TimeoutConfig{
376378
Timeout: 15 * time.Millisecond,
377379
}))
378380
e.Use(Logger())
379381
e.Use(Recover())
380382

383+
wg := sync.WaitGroup{}
384+
if tc.whenForceHandlerTimeout {
385+
wg.Add(1) // make `wg.Wait()` block until we release it with `wg.Done()`
386+
}
381387
e.GET("/", func(c echo.Context) error {
382-
var delay time.Duration
383-
if err := echo.QueryParamsBinder(c).Duration("delay", &delay).BindError(); err != nil {
384-
return err
385-
}
386-
if delay > 0 {
387-
time.Sleep(delay)
388-
}
388+
wg.Wait()
389389
return c.JSON(http.StatusTeapot, map[string]string{"message": "OK"})
390390
})
391391

@@ -401,6 +401,13 @@ func TestTimeoutWithFullEchoStack(t *testing.T) {
401401
assert.NoError(t, err)
402402
return
403403
}
404+
if tc.whenForceHandlerTimeout {
405+
wg.Done()
406+
// shutdown waits for server to shutdown. this way we wait logger mw to be executed
407+
ctx, cancel := context.WithTimeout(context.Background(), 150*time.Millisecond)
408+
defer cancel()
409+
server.Shutdown(ctx)
410+
}
404411

405412
assert.Equal(t, tc.expectStatusCode, res.StatusCode)
406413
if body, err := ioutil.ReadAll(res.Body); err == nil {
@@ -411,10 +418,10 @@ func TestTimeoutWithFullEchoStack(t *testing.T) {
411418

412419
logged := buf.String()
413420
for _, subStr := range tc.expectLogContains {
414-
assert.True(t, strings.Contains(logged, subStr))
421+
assert.True(t, strings.Contains(logged, subStr), "expected logs to contain: %v, logged: '%v'", subStr, logged)
415422
}
416423
for _, subStr := range tc.expectLogNotContains {
417-
assert.False(t, strings.Contains(logged, subStr))
424+
assert.False(t, strings.Contains(logged, subStr), "expected logs not to contain: %v, logged: '%v'", subStr, logged)
418425
}
419426
})
420427
}

0 commit comments

Comments
 (0)