recovery_test.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
  2. // Use of this source code is governed by a MIT style
  3. // license that can be found in the LICENSE file.
  4. // +build go1.7
  5. package gin
  6. import (
  7. "bytes"
  8. "net"
  9. "net/http"
  10. "os"
  11. "strings"
  12. "syscall"
  13. "testing"
  14. "github.com/stretchr/testify/assert"
  15. )
  16. // TestPanicInHandler assert that panic has been recovered.
  17. func TestPanicInHandler(t *testing.T) {
  18. buffer := new(bytes.Buffer)
  19. router := New()
  20. router.Use(RecoveryWithWriter(buffer))
  21. router.GET("/recovery", func(_ *Context) {
  22. panic("Oupps, Houston, we have a problem")
  23. })
  24. // RUN
  25. w := performRequest(router, "GET", "/recovery")
  26. // TEST
  27. assert.Equal(t, http.StatusInternalServerError, w.Code)
  28. assert.Contains(t, buffer.String(), "panic recovered")
  29. assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem")
  30. assert.Contains(t, buffer.String(), "TestPanicInHandler")
  31. assert.NotContains(t, buffer.String(), "GET /recovery")
  32. // Debug mode prints the request
  33. SetMode(DebugMode)
  34. // RUN
  35. w = performRequest(router, "GET", "/recovery")
  36. // TEST
  37. assert.Equal(t, http.StatusInternalServerError, w.Code)
  38. assert.Contains(t, buffer.String(), "GET /recovery")
  39. }
  40. // TestPanicWithAbort assert that panic has been recovered even if context.Abort was used.
  41. func TestPanicWithAbort(t *testing.T) {
  42. router := New()
  43. router.Use(RecoveryWithWriter(nil))
  44. router.GET("/recovery", func(c *Context) {
  45. c.AbortWithStatus(http.StatusBadRequest)
  46. panic("Oupps, Houston, we have a problem")
  47. })
  48. // RUN
  49. w := performRequest(router, "GET", "/recovery")
  50. // TEST
  51. assert.Equal(t, http.StatusBadRequest, w.Code)
  52. }
  53. func TestSource(t *testing.T) {
  54. bs := source(nil, 0)
  55. assert.Equal(t, []byte("???"), bs)
  56. in := [][]byte{
  57. []byte("Hello world."),
  58. []byte("Hi, gin.."),
  59. }
  60. bs = source(in, 10)
  61. assert.Equal(t, []byte("???"), bs)
  62. bs = source(in, 1)
  63. assert.Equal(t, []byte("Hello world."), bs)
  64. }
  65. func TestFunction(t *testing.T) {
  66. bs := function(1)
  67. assert.Equal(t, []byte("???"), bs)
  68. }
  69. // TestPanicWithBrokenPipe asserts that recovery specifically handles
  70. // writing responses to broken pipes
  71. func TestPanicWithBrokenPipe(t *testing.T) {
  72. const expectCode = 204
  73. expectMsgs := map[syscall.Errno]string{
  74. syscall.EPIPE: "broken pipe",
  75. syscall.ECONNRESET: "connection reset by peer",
  76. }
  77. for errno, expectMsg := range expectMsgs {
  78. t.Run(expectMsg, func(t *testing.T) {
  79. var buf bytes.Buffer
  80. router := New()
  81. router.Use(RecoveryWithWriter(&buf))
  82. router.GET("/recovery", func(c *Context) {
  83. // Start writing response
  84. c.Header("X-Test", "Value")
  85. c.Status(expectCode)
  86. // Oops. Client connection closed
  87. e := &net.OpError{Err: &os.SyscallError{Err: errno}}
  88. panic(e)
  89. })
  90. // RUN
  91. w := performRequest(router, "GET", "/recovery")
  92. // TEST
  93. assert.Equal(t, expectCode, w.Code)
  94. assert.Contains(t, strings.ToLower(buf.String()), expectMsg)
  95. })
  96. }
  97. }