recovery_test.go 2.8 KB

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