github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin/recovery_test.go (about) 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 5 package gin 6 7 import ( 8 "bytes" 9 "fmt" 10 "net" 11 "github.com/hellobchain/newcryptosm/http" 12 "os" 13 "strings" 14 "syscall" 15 "testing" 16 17 "github.com/stretchr/testify/assert" 18 ) 19 20 func TestPanicClean(t *testing.T) { 21 buffer := new(bytes.Buffer) 22 router := New() 23 password := "my-super-secret-password" 24 router.Use(RecoveryWithWriter(buffer)) 25 router.GET("/recovery", func(c *Context) { 26 c.AbortWithStatus(http.StatusBadRequest) 27 panic("Oupps, Houston, we have a problem") 28 }) 29 // RUN 30 w := performRequest(router, "GET", "/recovery", 31 header{ 32 Key: "Host", 33 Value: "www.google.com", 34 }, 35 header{ 36 Key: "Authorization", 37 Value: fmt.Sprintf("Bearer %s", password), 38 }, 39 header{ 40 Key: "Content-Type", 41 Value: "application/json", 42 }, 43 ) 44 // TEST 45 assert.Equal(t, http.StatusBadRequest, w.Code) 46 47 // Check the buffer does not have the secret key 48 assert.NotContains(t, buffer.String(), password) 49 } 50 51 // TestPanicInHandler assert that panic has been recovered. 52 func TestPanicInHandler(t *testing.T) { 53 buffer := new(bytes.Buffer) 54 router := New() 55 router.Use(RecoveryWithWriter(buffer)) 56 router.GET("/recovery", func(_ *Context) { 57 panic("Oupps, Houston, we have a problem") 58 }) 59 // RUN 60 w := performRequest(router, "GET", "/recovery") 61 // TEST 62 assert.Equal(t, http.StatusInternalServerError, w.Code) 63 assert.Contains(t, buffer.String(), "panic recovered") 64 assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem") 65 assert.Contains(t, buffer.String(), t.Name()) 66 assert.NotContains(t, buffer.String(), "GET /recovery") 67 68 // Debug mode prints the request 69 SetMode(DebugMode) 70 // RUN 71 w = performRequest(router, "GET", "/recovery") 72 // TEST 73 assert.Equal(t, http.StatusInternalServerError, w.Code) 74 assert.Contains(t, buffer.String(), "GET /recovery") 75 76 SetMode(TestMode) 77 } 78 79 // TestPanicWithAbort assert that panic has been recovered even if context.Abort was used. 80 func TestPanicWithAbort(t *testing.T) { 81 router := New() 82 router.Use(RecoveryWithWriter(nil)) 83 router.GET("/recovery", func(c *Context) { 84 c.AbortWithStatus(http.StatusBadRequest) 85 panic("Oupps, Houston, we have a problem") 86 }) 87 // RUN 88 w := performRequest(router, "GET", "/recovery") 89 // TEST 90 assert.Equal(t, http.StatusBadRequest, w.Code) 91 } 92 93 func TestSource(t *testing.T) { 94 bs := source(nil, 0) 95 assert.Equal(t, []byte("???"), bs) 96 97 in := [][]byte{ 98 []byte("Hello world."), 99 []byte("Hi, gin.."), 100 } 101 bs = source(in, 10) 102 assert.Equal(t, []byte("???"), bs) 103 104 bs = source(in, 1) 105 assert.Equal(t, []byte("Hello world."), bs) 106 } 107 108 func TestFunction(t *testing.T) { 109 bs := function(1) 110 assert.Equal(t, []byte("???"), bs) 111 } 112 113 // TestPanicWithBrokenPipe asserts that recovery specifically handles 114 // writing responses to broken pipes 115 func TestPanicWithBrokenPipe(t *testing.T) { 116 const expectCode = 204 117 118 expectMsgs := map[syscall.Errno]string{ 119 syscall.EPIPE: "broken pipe", 120 syscall.ECONNRESET: "connection reset by peer", 121 } 122 123 for errno, expectMsg := range expectMsgs { 124 t.Run(expectMsg, func(t *testing.T) { 125 126 var buf bytes.Buffer 127 128 router := New() 129 router.Use(RecoveryWithWriter(&buf)) 130 router.GET("/recovery", func(c *Context) { 131 // Start writing response 132 c.Header("X-Test", "Value") 133 c.Status(expectCode) 134 135 // Oops. Client connection closed 136 e := &net.OpError{Err: &os.SyscallError{Err: errno}} 137 panic(e) 138 }) 139 // RUN 140 w := performRequest(router, "GET", "/recovery") 141 // TEST 142 assert.Equal(t, expectCode, w.Code) 143 assert.Contains(t, strings.ToLower(buf.String()), expectMsg) 144 }) 145 } 146 } 147 148 func TestCustomRecoveryWithWriter(t *testing.T) { 149 errBuffer := new(bytes.Buffer) 150 buffer := new(bytes.Buffer) 151 router := New() 152 handleRecovery := func(c *Context, err interface{}) { 153 errBuffer.WriteString(err.(string)) 154 c.AbortWithStatus(http.StatusBadRequest) 155 } 156 router.Use(CustomRecoveryWithWriter(buffer, handleRecovery)) 157 router.GET("/recovery", func(_ *Context) { 158 panic("Oupps, Houston, we have a problem") 159 }) 160 // RUN 161 w := performRequest(router, "GET", "/recovery") 162 // TEST 163 assert.Equal(t, http.StatusBadRequest, w.Code) 164 assert.Contains(t, buffer.String(), "panic recovered") 165 assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem") 166 assert.Contains(t, buffer.String(), t.Name()) 167 assert.NotContains(t, buffer.String(), "GET /recovery") 168 169 // Debug mode prints the request 170 SetMode(DebugMode) 171 // RUN 172 w = performRequest(router, "GET", "/recovery") 173 // TEST 174 assert.Equal(t, http.StatusBadRequest, w.Code) 175 assert.Contains(t, buffer.String(), "GET /recovery") 176 177 assert.Equal(t, strings.Repeat("Oupps, Houston, we have a problem", 2), errBuffer.String()) 178 179 SetMode(TestMode) 180 } 181 182 func TestCustomRecovery(t *testing.T) { 183 errBuffer := new(bytes.Buffer) 184 buffer := new(bytes.Buffer) 185 router := New() 186 DefaultErrorWriter = buffer 187 handleRecovery := func(c *Context, err interface{}) { 188 errBuffer.WriteString(err.(string)) 189 c.AbortWithStatus(http.StatusBadRequest) 190 } 191 router.Use(CustomRecovery(handleRecovery)) 192 router.GET("/recovery", func(_ *Context) { 193 panic("Oupps, Houston, we have a problem") 194 }) 195 // RUN 196 w := performRequest(router, "GET", "/recovery") 197 // TEST 198 assert.Equal(t, http.StatusBadRequest, w.Code) 199 assert.Contains(t, buffer.String(), "panic recovered") 200 assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem") 201 assert.Contains(t, buffer.String(), t.Name()) 202 assert.NotContains(t, buffer.String(), "GET /recovery") 203 204 // Debug mode prints the request 205 SetMode(DebugMode) 206 // RUN 207 w = performRequest(router, "GET", "/recovery") 208 // TEST 209 assert.Equal(t, http.StatusBadRequest, w.Code) 210 assert.Contains(t, buffer.String(), "GET /recovery") 211 212 assert.Equal(t, strings.Repeat("Oupps, Houston, we have a problem", 2), errBuffer.String()) 213 214 SetMode(TestMode) 215 } 216 217 func TestRecoveryWithWriterWithCustomRecovery(t *testing.T) { 218 errBuffer := new(bytes.Buffer) 219 buffer := new(bytes.Buffer) 220 router := New() 221 DefaultErrorWriter = buffer 222 handleRecovery := func(c *Context, err interface{}) { 223 errBuffer.WriteString(err.(string)) 224 c.AbortWithStatus(http.StatusBadRequest) 225 } 226 router.Use(RecoveryWithWriter(DefaultErrorWriter, handleRecovery)) 227 router.GET("/recovery", func(_ *Context) { 228 panic("Oupps, Houston, we have a problem") 229 }) 230 // RUN 231 w := performRequest(router, "GET", "/recovery") 232 // TEST 233 assert.Equal(t, http.StatusBadRequest, w.Code) 234 assert.Contains(t, buffer.String(), "panic recovered") 235 assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem") 236 assert.Contains(t, buffer.String(), t.Name()) 237 assert.NotContains(t, buffer.String(), "GET /recovery") 238 239 // Debug mode prints the request 240 SetMode(DebugMode) 241 // RUN 242 w = performRequest(router, "GET", "/recovery") 243 // TEST 244 assert.Equal(t, http.StatusBadRequest, w.Code) 245 assert.Contains(t, buffer.String(), "GET /recovery") 246 247 assert.Equal(t, strings.Repeat("Oupps, Houston, we have a problem", 2), errBuffer.String()) 248 249 SetMode(TestMode) 250 }