recovery_test.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. package gin
  5. import (
  6. "bytes"
  7. "fmt"
  8. "net"
  9. "net/http"
  10. "os"
  11. "strings"
  12. "syscall"
  13. "testing"
  14. "github.com/stretchr/testify/assert"
  15. )
  16. func TestPanicClean(t *testing.T) {
  17. buffer := new(bytes.Buffer)
  18. router := New()
  19. password := "my-super-secret-password"
  20. router.Use(RecoveryWithWriter(buffer))
  21. router.GET("/recovery", func(c *Context) {
  22. c.AbortWithStatus(http.StatusBadRequest)
  23. panic("Oupps, Houston, we have a problem")
  24. })
  25. // RUN
  26. w := performRequest(router, "GET", "/recovery",
  27. header{
  28. Key: "Host",
  29. Value: "www.google.com",
  30. },
  31. header{
  32. Key: "Authorization",
  33. Value: fmt.Sprintf("Bearer %s", password),
  34. },
  35. header{
  36. Key: "Content-Type",
  37. Value: "application/json",
  38. },
  39. )
  40. // TEST
  41. assert.Equal(t, http.StatusBadRequest, w.Code)
  42. // Check the buffer does not have the secret key
  43. assert.NotContains(t, buffer.String(), password)
  44. }
  45. // TestPanicInHandler assert that panic has been recovered.
  46. func TestPanicInHandler(t *testing.T) {
  47. buffer := new(bytes.Buffer)
  48. router := New()
  49. router.Use(RecoveryWithWriter(buffer))
  50. router.GET("/recovery", func(_ *Context) {
  51. panic("Oupps, Houston, we have a problem")
  52. })
  53. // RUN
  54. w := performRequest(router, "GET", "/recovery")
  55. // TEST
  56. assert.Equal(t, http.StatusInternalServerError, w.Code)
  57. assert.Contains(t, buffer.String(), "panic recovered")
  58. assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem")
  59. assert.Contains(t, buffer.String(), "TestPanicInHandler")
  60. assert.NotContains(t, buffer.String(), "GET /recovery")
  61. // Debug mode prints the request
  62. SetMode(DebugMode)
  63. // RUN
  64. w = performRequest(router, "GET", "/recovery")
  65. // TEST
  66. assert.Equal(t, http.StatusInternalServerError, w.Code)
  67. assert.Contains(t, buffer.String(), "GET /recovery")
  68. SetMode(TestMode)
  69. }
  70. // TestPanicWithAbort assert that panic has been recovered even if context.Abort was used.
  71. func TestPanicWithAbort(t *testing.T) {
  72. router := New()
  73. router.Use(RecoveryWithWriter(nil))
  74. router.GET("/recovery", func(c *Context) {
  75. c.AbortWithStatus(http.StatusBadRequest)
  76. panic("Oupps, Houston, we have a problem")
  77. })
  78. // RUN
  79. w := performRequest(router, "GET", "/recovery")
  80. // TEST
  81. assert.Equal(t, http.StatusBadRequest, w.Code)
  82. }
  83. func TestSource(t *testing.T) {
  84. bs := source(nil, 0)
  85. assert.Equal(t, []byte("???"), bs)
  86. in := [][]byte{
  87. []byte("Hello world."),
  88. []byte("Hi, gin.."),
  89. }
  90. bs = source(in, 10)
  91. assert.Equal(t, []byte("???"), bs)
  92. bs = source(in, 1)
  93. assert.Equal(t, []byte("Hello world."), bs)
  94. }
  95. func TestFunction(t *testing.T) {
  96. bs := function(1)
  97. assert.Equal(t, []byte("???"), bs)
  98. }
  99. // TestPanicWithBrokenPipe asserts that recovery specifically handles
  100. // writing responses to broken pipes
  101. func TestPanicWithBrokenPipe(t *testing.T) {
  102. const expectCode = 204
  103. expectMsgs := map[syscall.Errno]string{
  104. syscall.EPIPE: "broken pipe",
  105. syscall.ECONNRESET: "connection reset by peer",
  106. }
  107. for errno, expectMsg := range expectMsgs {
  108. t.Run(expectMsg, func(t *testing.T) {
  109. var buf bytes.Buffer
  110. router := New()
  111. router.Use(RecoveryWithWriter(&buf))
  112. router.GET("/recovery", func(c *Context) {
  113. // Start writing response
  114. c.Header("X-Test", "Value")
  115. c.Status(expectCode)
  116. // Oops. Client connection closed
  117. e := &net.OpError{Err: &os.SyscallError{Err: errno}}
  118. panic(e)
  119. })
  120. // RUN
  121. w := performRequest(router, "GET", "/recovery")
  122. // TEST
  123. assert.Equal(t, expectCode, w.Code)
  124. assert.Contains(t, strings.ToLower(buf.String()), expectMsg)
  125. })
  126. }
  127. }