recovery_test.go 3.6 KB

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