@@ -2,6 +2,7 @@ package middleware
22
33import (
44 "bytes"
5+ "context"
56 "errors"
67 "fmt"
78 "io/ioutil"
@@ -328,12 +329,13 @@ func TestTimeoutCanHandleContextDeadlineOnNextHandler(t *testing.T) {
328329func 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