@@ -328,12 +328,13 @@ func TestTimeoutCanHandleContextDeadlineOnNextHandler(t *testing.T) {
328
328
func TestTimeoutWithFullEchoStack (t * testing.T ) {
329
329
// test timeout with full http server stack running, do see what http.Server.ErrorLog contains
330
330
var testCases = []struct {
331
- name string
332
- whenPath string
333
- expectStatusCode int
334
- expectResponse string
335
- expectLogContains []string
336
- expectLogNotContains []string
331
+ name string
332
+ whenPath string
333
+ whenForceHandlerTimeout bool
334
+ expectStatusCode int
335
+ expectResponse string
336
+ expectLogContains []string
337
+ expectLogNotContains []string
337
338
}{
338
339
{
339
340
name : "404 - write response in global error handler" ,
@@ -352,10 +353,11 @@ func TestTimeoutWithFullEchoStack(t *testing.T) {
352
353
expectLogContains : []string {`"status":418,"error":"",` },
353
354
},
354
355
{
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 ,
356
+ name : "503 - handler timeouts, write response in timeout middleware" ,
357
+ whenForceHandlerTimeout : true ,
358
+ whenPath : "/" ,
359
+ expectResponse : "<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>" ,
360
+ expectStatusCode : http .StatusServiceUnavailable ,
359
361
expectLogNotContains : []string {
360
362
"echo:http: superfluous response.WriteHeader call from" ,
361
363
"{" , // means that logger was not called.
@@ -371,21 +373,18 @@ func TestTimeoutWithFullEchoStack(t *testing.T) {
371
373
e .Logger .SetOutput (buf )
372
374
373
375
// 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.
375
376
e .Use (TimeoutWithConfig (TimeoutConfig {
376
377
Timeout : 15 * time .Millisecond ,
377
378
}))
378
379
e .Use (Logger ())
379
380
e .Use (Recover ())
380
381
382
+ wg := sync.WaitGroup {}
383
+ if tc .whenForceHandlerTimeout {
384
+ wg .Add (1 ) // make `wg.Wait()` block until we release it with `wg.Done()`
385
+ }
381
386
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
- }
387
+ wg .Wait ()
389
388
return c .JSON (http .StatusTeapot , map [string ]string {"message" : "OK" })
390
389
})
391
390
@@ -401,6 +400,9 @@ func TestTimeoutWithFullEchoStack(t *testing.T) {
401
400
assert .NoError (t , err )
402
401
return
403
402
}
403
+ if tc .whenForceHandlerTimeout {
404
+ wg .Done ()
405
+ }
404
406
405
407
assert .Equal (t , tc .expectStatusCode , res .StatusCode )
406
408
if body , err := ioutil .ReadAll (res .Body ); err == nil {
@@ -411,10 +413,10 @@ func TestTimeoutWithFullEchoStack(t *testing.T) {
411
413
412
414
logged := buf .String ()
413
415
for _ , subStr := range tc .expectLogContains {
414
- assert .True (t , strings .Contains (logged , subStr ))
416
+ assert .True (t , strings .Contains (logged , subStr ), "expected logs to contain: %v, logged: '%v'" , subStr , logged )
415
417
}
416
418
for _ , subStr := range tc .expectLogNotContains {
417
- assert .False (t , strings .Contains (logged , subStr ))
419
+ assert .False (t , strings .Contains (logged , subStr ), "expected logs not to contain: %v, logged: '%v'" , subStr , logged )
418
420
}
419
421
})
420
422
}
0 commit comments