routes_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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. "fmt"
  7. "io/ioutil"
  8. "net/http"
  9. "net/http/httptest"
  10. "os"
  11. "path/filepath"
  12. "testing"
  13. "github.com/stretchr/testify/assert"
  14. )
  15. func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
  16. req, _ := http.NewRequest(method, path, nil)
  17. w := httptest.NewRecorder()
  18. r.ServeHTTP(w, req)
  19. return w
  20. }
  21. func testRouteOK(method string, t *testing.T) {
  22. passed := false
  23. passedAny := false
  24. r := New()
  25. r.Any("/test2", func(c *Context) {
  26. passedAny = true
  27. })
  28. r.Handle(method, "/test", func(c *Context) {
  29. passed = true
  30. })
  31. w := performRequest(r, method, "/test")
  32. assert.True(t, passed)
  33. assert.Equal(t, http.StatusOK, w.Code)
  34. performRequest(r, method, "/test2")
  35. assert.True(t, passedAny)
  36. }
  37. // TestSingleRouteOK tests that POST route is correctly invoked.
  38. func testRouteNotOK(method string, t *testing.T) {
  39. passed := false
  40. router := New()
  41. router.Handle(method, "/test_2", func(c *Context) {
  42. passed = true
  43. })
  44. w := performRequest(router, method, "/test")
  45. assert.False(t, passed)
  46. assert.Equal(t, http.StatusNotFound, w.Code)
  47. }
  48. // TestSingleRouteOK tests that POST route is correctly invoked.
  49. func testRouteNotOK2(method string, t *testing.T) {
  50. passed := false
  51. router := New()
  52. router.HandleMethodNotAllowed = true
  53. var methodRoute string
  54. if method == "POST" {
  55. methodRoute = "GET"
  56. } else {
  57. methodRoute = "POST"
  58. }
  59. router.Handle(methodRoute, "/test", func(c *Context) {
  60. passed = true
  61. })
  62. w := performRequest(router, method, "/test")
  63. assert.False(t, passed)
  64. assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
  65. }
  66. func TestRouterMethod(t *testing.T) {
  67. router := New()
  68. router.PUT("/hey2", func(c *Context) {
  69. c.String(http.StatusOK, "sup2")
  70. })
  71. router.PUT("/hey", func(c *Context) {
  72. c.String(http.StatusOK, "called")
  73. })
  74. router.PUT("/hey3", func(c *Context) {
  75. c.String(http.StatusOK, "sup3")
  76. })
  77. w := performRequest(router, "PUT", "/hey")
  78. assert.Equal(t, http.StatusOK, w.Code)
  79. assert.Equal(t, "called", w.Body.String())
  80. }
  81. func TestRouterGroupRouteOK(t *testing.T) {
  82. testRouteOK("GET", t)
  83. testRouteOK("POST", t)
  84. testRouteOK("PUT", t)
  85. testRouteOK("PATCH", t)
  86. testRouteOK("HEAD", t)
  87. testRouteOK("OPTIONS", t)
  88. testRouteOK("DELETE", t)
  89. testRouteOK("CONNECT", t)
  90. testRouteOK("TRACE", t)
  91. }
  92. func TestRouteNotOK(t *testing.T) {
  93. testRouteNotOK("GET", t)
  94. testRouteNotOK("POST", t)
  95. testRouteNotOK("PUT", t)
  96. testRouteNotOK("PATCH", t)
  97. testRouteNotOK("HEAD", t)
  98. testRouteNotOK("OPTIONS", t)
  99. testRouteNotOK("DELETE", t)
  100. testRouteNotOK("CONNECT", t)
  101. testRouteNotOK("TRACE", t)
  102. }
  103. func TestRouteNotOK2(t *testing.T) {
  104. testRouteNotOK2("GET", t)
  105. testRouteNotOK2("POST", t)
  106. testRouteNotOK2("PUT", t)
  107. testRouteNotOK2("PATCH", t)
  108. testRouteNotOK2("HEAD", t)
  109. testRouteNotOK2("OPTIONS", t)
  110. testRouteNotOK2("DELETE", t)
  111. testRouteNotOK2("CONNECT", t)
  112. testRouteNotOK2("TRACE", t)
  113. }
  114. func TestRouteRedirectTrailingSlash(t *testing.T) {
  115. router := New()
  116. router.RedirectFixedPath = false
  117. router.RedirectTrailingSlash = true
  118. router.GET("/path", func(c *Context) {})
  119. router.GET("/path2/", func(c *Context) {})
  120. router.POST("/path3", func(c *Context) {})
  121. router.PUT("/path4/", func(c *Context) {})
  122. w := performRequest(router, "GET", "/path/")
  123. assert.Equal(t, "/path", w.Header().Get("Location"))
  124. assert.Equal(t, http.StatusMovedPermanently, w.Code)
  125. w = performRequest(router, "GET", "/path2")
  126. assert.Equal(t, "/path2/", w.Header().Get("Location"))
  127. assert.Equal(t, http.StatusMovedPermanently, w.Code)
  128. w = performRequest(router, "POST", "/path3/")
  129. assert.Equal(t, "/path3", w.Header().Get("Location"))
  130. assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
  131. w = performRequest(router, "PUT", "/path4")
  132. assert.Equal(t, "/path4/", w.Header().Get("Location"))
  133. assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
  134. w = performRequest(router, "GET", "/path")
  135. assert.Equal(t, http.StatusOK, w.Code)
  136. w = performRequest(router, "GET", "/path2/")
  137. assert.Equal(t, http.StatusOK, w.Code)
  138. w = performRequest(router, "POST", "/path3")
  139. assert.Equal(t, http.StatusOK, w.Code)
  140. w = performRequest(router, "PUT", "/path4/")
  141. assert.Equal(t, http.StatusOK, w.Code)
  142. router.RedirectTrailingSlash = false
  143. w = performRequest(router, "GET", "/path/")
  144. assert.Equal(t, http.StatusNotFound, w.Code)
  145. w = performRequest(router, "GET", "/path2")
  146. assert.Equal(t, http.StatusNotFound, w.Code)
  147. w = performRequest(router, "POST", "/path3/")
  148. assert.Equal(t, http.StatusNotFound, w.Code)
  149. w = performRequest(router, "PUT", "/path4")
  150. assert.Equal(t, http.StatusNotFound, w.Code)
  151. }
  152. func TestRouteRedirectFixedPath(t *testing.T) {
  153. router := New()
  154. router.RedirectFixedPath = true
  155. router.RedirectTrailingSlash = false
  156. router.GET("/path", func(c *Context) {})
  157. router.GET("/Path2", func(c *Context) {})
  158. router.POST("/PATH3", func(c *Context) {})
  159. router.POST("/Path4/", func(c *Context) {})
  160. w := performRequest(router, "GET", "/PATH")
  161. assert.Equal(t, "/path", w.Header().Get("Location"))
  162. assert.Equal(t, http.StatusMovedPermanently, w.Code)
  163. w = performRequest(router, "GET", "/path2")
  164. assert.Equal(t, "/Path2", w.Header().Get("Location"))
  165. assert.Equal(t, http.StatusMovedPermanently, w.Code)
  166. w = performRequest(router, "POST", "/path3")
  167. assert.Equal(t, "/PATH3", w.Header().Get("Location"))
  168. assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
  169. w = performRequest(router, "POST", "/path4")
  170. assert.Equal(t, "/Path4/", w.Header().Get("Location"))
  171. assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
  172. }
  173. // TestContextParamsGet tests that a parameter can be parsed from the URL.
  174. func TestRouteParamsByName(t *testing.T) {
  175. name := ""
  176. lastName := ""
  177. wild := ""
  178. router := New()
  179. router.GET("/test/:name/:last_name/*wild", func(c *Context) {
  180. name = c.Params.ByName("name")
  181. lastName = c.Params.ByName("last_name")
  182. var ok bool
  183. wild, ok = c.Params.Get("wild")
  184. assert.True(t, ok)
  185. assert.Equal(t, name, c.Param("name"))
  186. assert.Equal(t, name, c.Param("name"))
  187. assert.Equal(t, lastName, c.Param("last_name"))
  188. assert.Empty(t, c.Param("wtf"))
  189. assert.Empty(t, c.Params.ByName("wtf"))
  190. wtf, ok := c.Params.Get("wtf")
  191. assert.Empty(t, wtf)
  192. assert.False(t, ok)
  193. })
  194. w := performRequest(router, "GET", "/test/john/smith/is/super/great")
  195. assert.Equal(t, http.StatusOK, w.Code)
  196. assert.Equal(t, "john", name)
  197. assert.Equal(t, "smith", lastName)
  198. assert.Equal(t, "/is/super/great", wild)
  199. }
  200. // TestHandleStaticFile - ensure the static file handles properly
  201. func TestRouteStaticFile(t *testing.T) {
  202. // SETUP file
  203. testRoot, _ := os.Getwd()
  204. f, err := ioutil.TempFile(testRoot, "")
  205. if err != nil {
  206. t.Error(err)
  207. }
  208. defer os.Remove(f.Name())
  209. f.WriteString("Gin Web Framework")
  210. f.Close()
  211. dir, filename := filepath.Split(f.Name())
  212. // SETUP gin
  213. router := New()
  214. router.Static("/using_static", dir)
  215. router.StaticFile("/result", f.Name())
  216. w := performRequest(router, "GET", "/using_static/"+filename)
  217. w2 := performRequest(router, "GET", "/result")
  218. assert.Equal(t, w, w2)
  219. assert.Equal(t, http.StatusOK, w.Code)
  220. assert.Equal(t, "Gin Web Framework", w.Body.String())
  221. assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
  222. w3 := performRequest(router, "HEAD", "/using_static/"+filename)
  223. w4 := performRequest(router, "HEAD", "/result")
  224. assert.Equal(t, w3, w4)
  225. assert.Equal(t, http.StatusOK, w3.Code)
  226. }
  227. // TestHandleStaticDir - ensure the root/sub dir handles properly
  228. func TestRouteStaticListingDir(t *testing.T) {
  229. router := New()
  230. router.StaticFS("/", Dir("./", true))
  231. w := performRequest(router, "GET", "/")
  232. assert.Equal(t, http.StatusOK, w.Code)
  233. assert.Contains(t, w.Body.String(), "gin.go")
  234. assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
  235. }
  236. // TestHandleHeadToDir - ensure the root/sub dir handles properly
  237. func TestRouteStaticNoListing(t *testing.T) {
  238. router := New()
  239. router.Static("/", "./")
  240. w := performRequest(router, "GET", "/")
  241. assert.Equal(t, http.StatusNotFound, w.Code)
  242. assert.NotContains(t, w.Body.String(), "gin.go")
  243. }
  244. func TestRouterMiddlewareAndStatic(t *testing.T) {
  245. router := New()
  246. static := router.Group("/", func(c *Context) {
  247. c.Writer.Header().Add("Last-Modified", "Mon, 02 Jan 2006 15:04:05 MST")
  248. c.Writer.Header().Add("Expires", "Mon, 02 Jan 2006 15:04:05 MST")
  249. c.Writer.Header().Add("X-GIN", "Gin Framework")
  250. })
  251. static.Static("/", "./")
  252. w := performRequest(router, "GET", "/gin.go")
  253. assert.Equal(t, http.StatusOK, w.Code)
  254. assert.Contains(t, w.Body.String(), "package gin")
  255. assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
  256. assert.NotEqual(t, w.Header().Get("Last-Modified"), "Mon, 02 Jan 2006 15:04:05 MST")
  257. assert.Equal(t, "Mon, 02 Jan 2006 15:04:05 MST", w.Header().Get("Expires"))
  258. assert.Equal(t, "Gin Framework", w.Header().Get("x-GIN"))
  259. }
  260. func TestRouteNotAllowedEnabled(t *testing.T) {
  261. router := New()
  262. router.HandleMethodNotAllowed = true
  263. router.POST("/path", func(c *Context) {})
  264. w := performRequest(router, "GET", "/path")
  265. assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
  266. router.NoMethod(func(c *Context) {
  267. c.String(http.StatusTeapot, "responseText")
  268. })
  269. w = performRequest(router, "GET", "/path")
  270. assert.Equal(t, "responseText", w.Body.String())
  271. assert.Equal(t, http.StatusTeapot, w.Code)
  272. }
  273. func TestRouteNotAllowedEnabled2(t *testing.T) {
  274. router := New()
  275. router.HandleMethodNotAllowed = true
  276. // add one methodTree to trees
  277. router.addRoute("POST", "/", HandlersChain{func(_ *Context) {}})
  278. router.GET("/path2", func(c *Context) {})
  279. w := performRequest(router, "POST", "/path2")
  280. assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
  281. }
  282. func TestRouteNotAllowedDisabled(t *testing.T) {
  283. router := New()
  284. router.HandleMethodNotAllowed = false
  285. router.POST("/path", func(c *Context) {})
  286. w := performRequest(router, "GET", "/path")
  287. assert.Equal(t, http.StatusNotFound, w.Code)
  288. router.NoMethod(func(c *Context) {
  289. c.String(http.StatusTeapot, "responseText")
  290. })
  291. w = performRequest(router, "GET", "/path")
  292. assert.Equal(t, "404 page not found", w.Body.String())
  293. assert.Equal(t, http.StatusNotFound, w.Code)
  294. }
  295. func TestRouterNotFound(t *testing.T) {
  296. router := New()
  297. router.RedirectFixedPath = true
  298. router.GET("/path", func(c *Context) {})
  299. router.GET("/dir/", func(c *Context) {})
  300. router.GET("/", func(c *Context) {})
  301. testRoutes := []struct {
  302. route string
  303. code int
  304. location string
  305. }{
  306. {"/path/", http.StatusMovedPermanently, "/path"}, // TSR -/
  307. {"/dir", http.StatusMovedPermanently, "/dir/"}, // TSR +/
  308. {"", http.StatusMovedPermanently, "/"}, // TSR +/
  309. {"/PATH", http.StatusMovedPermanently, "/path"}, // Fixed Case
  310. {"/DIR/", http.StatusMovedPermanently, "/dir/"}, // Fixed Case
  311. {"/PATH/", http.StatusMovedPermanently, "/path"}, // Fixed Case -/
  312. {"/DIR", http.StatusMovedPermanently, "/dir/"}, // Fixed Case +/
  313. {"/../path", http.StatusMovedPermanently, "/path"}, // CleanPath
  314. {"/nope", http.StatusNotFound, ""}, // NotFound
  315. }
  316. for _, tr := range testRoutes {
  317. w := performRequest(router, "GET", tr.route)
  318. assert.Equal(t, tr.code, w.Code)
  319. if w.Code != http.StatusNotFound {
  320. assert.Equal(t, tr.location, fmt.Sprint(w.Header().Get("Location")))
  321. }
  322. }
  323. // Test custom not found handler
  324. var notFound bool
  325. router.NoRoute(func(c *Context) {
  326. c.AbortWithStatus(http.StatusNotFound)
  327. notFound = true
  328. })
  329. w := performRequest(router, "GET", "/nope")
  330. assert.Equal(t, http.StatusNotFound, w.Code)
  331. assert.True(t, notFound)
  332. // Test other method than GET (want 307 instead of 301)
  333. router.PATCH("/path", func(c *Context) {})
  334. w = performRequest(router, "PATCH", "/path/")
  335. assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
  336. assert.Equal(t, "map[Location:[/path]]", fmt.Sprint(w.Header()))
  337. // Test special case where no node for the prefix "/" exists
  338. router = New()
  339. router.GET("/a", func(c *Context) {})
  340. w = performRequest(router, "GET", "/")
  341. assert.Equal(t, http.StatusNotFound, w.Code)
  342. }
  343. func TestRouteRawPath(t *testing.T) {
  344. route := New()
  345. route.UseRawPath = true
  346. route.POST("/project/:name/build/:num", func(c *Context) {
  347. name := c.Params.ByName("name")
  348. num := c.Params.ByName("num")
  349. assert.Equal(t, name, c.Param("name"))
  350. assert.Equal(t, num, c.Param("num"))
  351. assert.Equal(t, "Some/Other/Project", name)
  352. assert.Equal(t, "222", num)
  353. })
  354. w := performRequest(route, "POST", "/project/Some%2FOther%2FProject/build/222")
  355. assert.Equal(t, http.StatusOK, w.Code)
  356. }
  357. func TestRouteRawPathNoUnescape(t *testing.T) {
  358. route := New()
  359. route.UseRawPath = true
  360. route.UnescapePathValues = false
  361. route.POST("/project/:name/build/:num", func(c *Context) {
  362. name := c.Params.ByName("name")
  363. num := c.Params.ByName("num")
  364. assert.Equal(t, name, c.Param("name"))
  365. assert.Equal(t, num, c.Param("num"))
  366. assert.Equal(t, "Some%2FOther%2FProject", name)
  367. assert.Equal(t, "333", num)
  368. })
  369. w := performRequest(route, "POST", "/project/Some%2FOther%2FProject/build/333")
  370. assert.Equal(t, http.StatusOK, w.Code)
  371. }
  372. func TestRouteServeErrorWithWriteHeader(t *testing.T) {
  373. route := New()
  374. route.Use(func(c *Context) {
  375. c.Status(421)
  376. c.Next()
  377. })
  378. w := performRequest(route, "GET", "/NotFound")
  379. assert.Equal(t, 421, w.Code)
  380. assert.Equal(t, 0, w.Body.Len())
  381. }