recovery_test.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. SetMode(TestMode)
  40. }
  41. // TestPanicWithAbort assert that panic has been recovered even if context.Abort was used.
  42. func TestPanicWithAbort(t *testing.T) {
  43. router := New()
  44. router.Use(RecoveryWithWriter(nil))
  45. router.GET("/recovery", func(c *Context) {
  46. c.AbortWithStatus(http.StatusBadRequest)
  47. panic("Oupps, Houston, we have a problem")
  48. })
  49. // RUN
  50. w := performRequest(router, "GET", "/recovery")
  51. // TEST
  52. assert.Equal(t, http.StatusBadRequest, w.Code)
  53. }
  54. func TestSource(t *testing.T) {
  55. bs := source(nil, 0)
  56. assert.Equal(t, []byte("???"), bs)
  57. in := [][]byte{
  58. []byte("Hello world."),
  59. []byte("Hi, gin.."),
  60. }
  61. bs = source(in, 10)
  62. assert.Equal(t, []byte("???"), bs)
  63. bs = source(in, 1)
  64. assert.Equal(t, []byte("Hello world."), bs)
  65. }
  66. func TestFunction(t *testing.T) {
  67. bs := function(1)
  68. assert.Equal(t, []byte("???"), bs)
  69. }
  70. // TestPanicWithBrokenPipe asserts that recovery specifically handles
  71. // writing responses to broken pipes
  72. func TestPanicWithBrokenPipe(t *testing.T) {
  73. const expectCode = 204
  74. expectMsgs := map[syscall.Errno]string{
  75. syscall.EPIPE: "broken pipe",
  76. syscall.ECONNRESET: "connection reset by peer",
  77. }
  78. for errno, expectMsg := range expectMsgs {
  79. t.Run(expectMsg, func(t *testing.T) {
  80. var buf bytes.Buffer
  81. router := New()
  82. router.Use(RecoveryWithWriter(&buf))
  83. router.GET("/recovery", func(c *Context) {
  84. // Start writing response
  85. c.Header("X-Test", "Value")
  86. c.Status(expectCode)
  87. // Oops. Client connection closed
  88. e := &net.OpError{Err: &os.SyscallError{Err: errno}}
  89. panic(e)
  90. })
  91. // RUN
  92. w := performRequest(router, "GET", "/recovery")
  93. // TEST
  94. assert.Equal(t, expectCode, w.Code)
  95. assert.Contains(t, strings.ToLower(buf.String()), expectMsg)
  96. })
  97. }
  98. }