gin_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  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. "crypto/tls"
  7. "fmt"
  8. "html/template"
  9. "io/ioutil"
  10. "net/http"
  11. "net/http/httptest"
  12. "reflect"
  13. "strconv"
  14. "sync/atomic"
  15. "testing"
  16. "time"
  17. "github.com/stretchr/testify/assert"
  18. )
  19. func formatAsDate(t time.Time) string {
  20. year, month, day := t.Date()
  21. return fmt.Sprintf("%d/%02d/%02d", year, month, day)
  22. }
  23. func setupHTMLFiles(t *testing.T, mode string, tls bool, loadMethod func(*Engine)) *httptest.Server {
  24. SetMode(mode)
  25. defer SetMode(TestMode)
  26. var router *Engine
  27. captureOutput(t, func() {
  28. router = New()
  29. router.Delims("{[{", "}]}")
  30. router.SetFuncMap(template.FuncMap{
  31. "formatAsDate": formatAsDate,
  32. })
  33. loadMethod(router)
  34. router.GET("/test", func(c *Context) {
  35. c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
  36. })
  37. router.GET("/raw", func(c *Context) {
  38. c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
  39. "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
  40. })
  41. })
  42. })
  43. var ts *httptest.Server
  44. if tls {
  45. ts = httptest.NewTLSServer(router)
  46. } else {
  47. ts = httptest.NewServer(router)
  48. }
  49. return ts
  50. }
  51. func TestLoadHTMLGlobDebugMode(t *testing.T) {
  52. ts := setupHTMLFiles(
  53. t,
  54. DebugMode,
  55. false,
  56. func(router *Engine) {
  57. router.LoadHTMLGlob("./testdata/template/*")
  58. },
  59. )
  60. defer ts.Close()
  61. res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
  62. if err != nil {
  63. fmt.Println(err)
  64. }
  65. resp, _ := ioutil.ReadAll(res.Body)
  66. assert.Equal(t, "<h1>Hello world</h1>", string(resp))
  67. }
  68. func TestLoadHTMLGlobTestMode(t *testing.T) {
  69. ts := setupHTMLFiles(
  70. t,
  71. TestMode,
  72. false,
  73. func(router *Engine) {
  74. router.LoadHTMLGlob("./testdata/template/*")
  75. },
  76. )
  77. defer ts.Close()
  78. res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
  79. if err != nil {
  80. fmt.Println(err)
  81. }
  82. resp, _ := ioutil.ReadAll(res.Body)
  83. assert.Equal(t, "<h1>Hello world</h1>", string(resp))
  84. }
  85. func TestLoadHTMLGlobReleaseMode(t *testing.T) {
  86. ts := setupHTMLFiles(
  87. t,
  88. ReleaseMode,
  89. false,
  90. func(router *Engine) {
  91. router.LoadHTMLGlob("./testdata/template/*")
  92. },
  93. )
  94. defer ts.Close()
  95. res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
  96. if err != nil {
  97. fmt.Println(err)
  98. }
  99. resp, _ := ioutil.ReadAll(res.Body)
  100. assert.Equal(t, "<h1>Hello world</h1>", string(resp))
  101. }
  102. func TestLoadHTMLGlobUsingTLS(t *testing.T) {
  103. ts := setupHTMLFiles(
  104. t,
  105. DebugMode,
  106. true,
  107. func(router *Engine) {
  108. router.LoadHTMLGlob("./testdata/template/*")
  109. },
  110. )
  111. defer ts.Close()
  112. // Use InsecureSkipVerify for avoiding `x509: certificate signed by unknown authority` error
  113. tr := &http.Transport{
  114. TLSClientConfig: &tls.Config{
  115. InsecureSkipVerify: true,
  116. },
  117. }
  118. client := &http.Client{Transport: tr}
  119. res, err := client.Get(fmt.Sprintf("%s/test", ts.URL))
  120. if err != nil {
  121. fmt.Println(err)
  122. }
  123. resp, _ := ioutil.ReadAll(res.Body)
  124. assert.Equal(t, "<h1>Hello world</h1>", string(resp))
  125. }
  126. func TestLoadHTMLGlobFromFuncMap(t *testing.T) {
  127. ts := setupHTMLFiles(
  128. t,
  129. DebugMode,
  130. false,
  131. func(router *Engine) {
  132. router.LoadHTMLGlob("./testdata/template/*")
  133. },
  134. )
  135. defer ts.Close()
  136. res, err := http.Get(fmt.Sprintf("%s/raw", ts.URL))
  137. if err != nil {
  138. fmt.Println(err)
  139. }
  140. resp, _ := ioutil.ReadAll(res.Body)
  141. assert.Equal(t, "Date: 2017/07/01\n", string(resp))
  142. }
  143. func init() {
  144. SetMode(TestMode)
  145. }
  146. func TestCreateEngine(t *testing.T) {
  147. router := New()
  148. assert.Equal(t, "/", router.basePath)
  149. assert.Equal(t, router.engine, router)
  150. assert.Empty(t, router.Handlers)
  151. }
  152. func TestLoadHTMLFilesTestMode(t *testing.T) {
  153. ts := setupHTMLFiles(
  154. t,
  155. TestMode,
  156. false,
  157. func(router *Engine) {
  158. router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl")
  159. },
  160. )
  161. defer ts.Close()
  162. res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
  163. if err != nil {
  164. fmt.Println(err)
  165. }
  166. resp, _ := ioutil.ReadAll(res.Body)
  167. assert.Equal(t, "<h1>Hello world</h1>", string(resp))
  168. }
  169. func TestLoadHTMLFilesDebugMode(t *testing.T) {
  170. ts := setupHTMLFiles(
  171. t,
  172. DebugMode,
  173. false,
  174. func(router *Engine) {
  175. router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl")
  176. },
  177. )
  178. defer ts.Close()
  179. res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
  180. if err != nil {
  181. fmt.Println(err)
  182. }
  183. resp, _ := ioutil.ReadAll(res.Body)
  184. assert.Equal(t, "<h1>Hello world</h1>", string(resp))
  185. }
  186. func TestLoadHTMLFilesReleaseMode(t *testing.T) {
  187. ts := setupHTMLFiles(
  188. t,
  189. ReleaseMode,
  190. false,
  191. func(router *Engine) {
  192. router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl")
  193. },
  194. )
  195. defer ts.Close()
  196. res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
  197. if err != nil {
  198. fmt.Println(err)
  199. }
  200. resp, _ := ioutil.ReadAll(res.Body)
  201. assert.Equal(t, "<h1>Hello world</h1>", string(resp))
  202. }
  203. func TestLoadHTMLFilesUsingTLS(t *testing.T) {
  204. ts := setupHTMLFiles(
  205. t,
  206. TestMode,
  207. true,
  208. func(router *Engine) {
  209. router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl")
  210. },
  211. )
  212. defer ts.Close()
  213. // Use InsecureSkipVerify for avoiding `x509: certificate signed by unknown authority` error
  214. tr := &http.Transport{
  215. TLSClientConfig: &tls.Config{
  216. InsecureSkipVerify: true,
  217. },
  218. }
  219. client := &http.Client{Transport: tr}
  220. res, err := client.Get(fmt.Sprintf("%s/test", ts.URL))
  221. if err != nil {
  222. fmt.Println(err)
  223. }
  224. resp, _ := ioutil.ReadAll(res.Body)
  225. assert.Equal(t, "<h1>Hello world</h1>", string(resp))
  226. }
  227. func TestLoadHTMLFilesFuncMap(t *testing.T) {
  228. ts := setupHTMLFiles(
  229. t,
  230. TestMode,
  231. false,
  232. func(router *Engine) {
  233. router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl")
  234. },
  235. )
  236. defer ts.Close()
  237. res, err := http.Get(fmt.Sprintf("%s/raw", ts.URL))
  238. if err != nil {
  239. fmt.Println(err)
  240. }
  241. resp, _ := ioutil.ReadAll(res.Body)
  242. assert.Equal(t, "Date: 2017/07/01\n", string(resp))
  243. }
  244. func TestAddRoute(t *testing.T) {
  245. router := New()
  246. router.addRoute("GET", "/", HandlersChain{func(_ *Context) {}})
  247. assert.Len(t, router.trees, 1)
  248. assert.NotNil(t, router.trees.get("GET"))
  249. assert.Nil(t, router.trees.get("POST"))
  250. router.addRoute("POST", "/", HandlersChain{func(_ *Context) {}})
  251. assert.Len(t, router.trees, 2)
  252. assert.NotNil(t, router.trees.get("GET"))
  253. assert.NotNil(t, router.trees.get("POST"))
  254. router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
  255. assert.Len(t, router.trees, 2)
  256. }
  257. func TestAddRouteFails(t *testing.T) {
  258. router := New()
  259. assert.Panics(t, func() { router.addRoute("", "/", HandlersChain{func(_ *Context) {}}) })
  260. assert.Panics(t, func() { router.addRoute("GET", "a", HandlersChain{func(_ *Context) {}}) })
  261. assert.Panics(t, func() { router.addRoute("GET", "/", HandlersChain{}) })
  262. router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
  263. assert.Panics(t, func() {
  264. router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
  265. })
  266. }
  267. func TestCreateDefaultRouter(t *testing.T) {
  268. router := Default()
  269. assert.Len(t, router.Handlers, 2)
  270. }
  271. func TestNoRouteWithoutGlobalHandlers(t *testing.T) {
  272. var middleware0 HandlerFunc = func(c *Context) {}
  273. var middleware1 HandlerFunc = func(c *Context) {}
  274. router := New()
  275. router.NoRoute(middleware0)
  276. assert.Nil(t, router.Handlers)
  277. assert.Len(t, router.noRoute, 1)
  278. assert.Len(t, router.allNoRoute, 1)
  279. compareFunc(t, router.noRoute[0], middleware0)
  280. compareFunc(t, router.allNoRoute[0], middleware0)
  281. router.NoRoute(middleware1, middleware0)
  282. assert.Len(t, router.noRoute, 2)
  283. assert.Len(t, router.allNoRoute, 2)
  284. compareFunc(t, router.noRoute[0], middleware1)
  285. compareFunc(t, router.allNoRoute[0], middleware1)
  286. compareFunc(t, router.noRoute[1], middleware0)
  287. compareFunc(t, router.allNoRoute[1], middleware0)
  288. }
  289. func TestNoRouteWithGlobalHandlers(t *testing.T) {
  290. var middleware0 HandlerFunc = func(c *Context) {}
  291. var middleware1 HandlerFunc = func(c *Context) {}
  292. var middleware2 HandlerFunc = func(c *Context) {}
  293. router := New()
  294. router.Use(middleware2)
  295. router.NoRoute(middleware0)
  296. assert.Len(t, router.allNoRoute, 2)
  297. assert.Len(t, router.Handlers, 1)
  298. assert.Len(t, router.noRoute, 1)
  299. compareFunc(t, router.Handlers[0], middleware2)
  300. compareFunc(t, router.noRoute[0], middleware0)
  301. compareFunc(t, router.allNoRoute[0], middleware2)
  302. compareFunc(t, router.allNoRoute[1], middleware0)
  303. router.Use(middleware1)
  304. assert.Len(t, router.allNoRoute, 3)
  305. assert.Len(t, router.Handlers, 2)
  306. assert.Len(t, router.noRoute, 1)
  307. compareFunc(t, router.Handlers[0], middleware2)
  308. compareFunc(t, router.Handlers[1], middleware1)
  309. compareFunc(t, router.noRoute[0], middleware0)
  310. compareFunc(t, router.allNoRoute[0], middleware2)
  311. compareFunc(t, router.allNoRoute[1], middleware1)
  312. compareFunc(t, router.allNoRoute[2], middleware0)
  313. }
  314. func TestNoMethodWithoutGlobalHandlers(t *testing.T) {
  315. var middleware0 HandlerFunc = func(c *Context) {}
  316. var middleware1 HandlerFunc = func(c *Context) {}
  317. router := New()
  318. router.NoMethod(middleware0)
  319. assert.Empty(t, router.Handlers)
  320. assert.Len(t, router.noMethod, 1)
  321. assert.Len(t, router.allNoMethod, 1)
  322. compareFunc(t, router.noMethod[0], middleware0)
  323. compareFunc(t, router.allNoMethod[0], middleware0)
  324. router.NoMethod(middleware1, middleware0)
  325. assert.Len(t, router.noMethod, 2)
  326. assert.Len(t, router.allNoMethod, 2)
  327. compareFunc(t, router.noMethod[0], middleware1)
  328. compareFunc(t, router.allNoMethod[0], middleware1)
  329. compareFunc(t, router.noMethod[1], middleware0)
  330. compareFunc(t, router.allNoMethod[1], middleware0)
  331. }
  332. func TestRebuild404Handlers(t *testing.T) {
  333. }
  334. func TestNoMethodWithGlobalHandlers(t *testing.T) {
  335. var middleware0 HandlerFunc = func(c *Context) {}
  336. var middleware1 HandlerFunc = func(c *Context) {}
  337. var middleware2 HandlerFunc = func(c *Context) {}
  338. router := New()
  339. router.Use(middleware2)
  340. router.NoMethod(middleware0)
  341. assert.Len(t, router.allNoMethod, 2)
  342. assert.Len(t, router.Handlers, 1)
  343. assert.Len(t, router.noMethod, 1)
  344. compareFunc(t, router.Handlers[0], middleware2)
  345. compareFunc(t, router.noMethod[0], middleware0)
  346. compareFunc(t, router.allNoMethod[0], middleware2)
  347. compareFunc(t, router.allNoMethod[1], middleware0)
  348. router.Use(middleware1)
  349. assert.Len(t, router.allNoMethod, 3)
  350. assert.Len(t, router.Handlers, 2)
  351. assert.Len(t, router.noMethod, 1)
  352. compareFunc(t, router.Handlers[0], middleware2)
  353. compareFunc(t, router.Handlers[1], middleware1)
  354. compareFunc(t, router.noMethod[0], middleware0)
  355. compareFunc(t, router.allNoMethod[0], middleware2)
  356. compareFunc(t, router.allNoMethod[1], middleware1)
  357. compareFunc(t, router.allNoMethod[2], middleware0)
  358. }
  359. func compareFunc(t *testing.T, a, b interface{}) {
  360. sf1 := reflect.ValueOf(a)
  361. sf2 := reflect.ValueOf(b)
  362. if sf1.Pointer() != sf2.Pointer() {
  363. t.Error("different functions")
  364. }
  365. }
  366. func TestListOfRoutes(t *testing.T) {
  367. router := New()
  368. router.GET("/favicon.ico", handlerTest1)
  369. router.GET("/", handlerTest1)
  370. group := router.Group("/users")
  371. {
  372. group.GET("/", handlerTest2)
  373. group.GET("/:id", handlerTest1)
  374. group.POST("/:id", handlerTest2)
  375. }
  376. router.Static("/static", ".")
  377. list := router.Routes()
  378. assert.Len(t, list, 7)
  379. assertRoutePresent(t, list, RouteInfo{
  380. Method: "GET",
  381. Path: "/favicon.ico",
  382. Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest1$",
  383. })
  384. assertRoutePresent(t, list, RouteInfo{
  385. Method: "GET",
  386. Path: "/",
  387. Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest1$",
  388. })
  389. assertRoutePresent(t, list, RouteInfo{
  390. Method: "GET",
  391. Path: "/users/",
  392. Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest2$",
  393. })
  394. assertRoutePresent(t, list, RouteInfo{
  395. Method: "GET",
  396. Path: "/users/:id",
  397. Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest1$",
  398. })
  399. assertRoutePresent(t, list, RouteInfo{
  400. Method: "POST",
  401. Path: "/users/:id",
  402. Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest2$",
  403. })
  404. }
  405. func TestEngineHandleContext(t *testing.T) {
  406. r := New()
  407. r.GET("/", func(c *Context) {
  408. c.Request.URL.Path = "/v2"
  409. r.HandleContext(c)
  410. })
  411. v2 := r.Group("/v2")
  412. {
  413. v2.GET("/", func(c *Context) {})
  414. }
  415. assert.NotPanics(t, func() {
  416. w := performRequest(r, "GET", "/")
  417. assert.Equal(t, 301, w.Code)
  418. })
  419. }
  420. func TestEngineHandleContextManyReEntries(t *testing.T) {
  421. expectValue := 10000
  422. var handlerCounter, middlewareCounter int64
  423. r := New()
  424. r.Use(func(c *Context) {
  425. atomic.AddInt64(&middlewareCounter, 1)
  426. })
  427. r.GET("/:count", func(c *Context) {
  428. countStr := c.Param("count")
  429. count, err := strconv.Atoi(countStr)
  430. assert.NoError(t, err)
  431. n, err := c.Writer.Write([]byte("."))
  432. assert.NoError(t, err)
  433. assert.Equal(t, 1, n)
  434. switch {
  435. case count > 0:
  436. c.Request.URL.Path = "/" + strconv.Itoa(count-1)
  437. r.HandleContext(c)
  438. }
  439. }, func(c *Context) {
  440. atomic.AddInt64(&handlerCounter, 1)
  441. })
  442. assert.NotPanics(t, func() {
  443. w := performRequest(r, "GET", "/"+strconv.Itoa(expectValue-1)) // include 0 value
  444. assert.Equal(t, 200, w.Code)
  445. assert.Equal(t, expectValue, w.Body.Len())
  446. })
  447. assert.Equal(t, int64(expectValue), handlerCounter)
  448. assert.Equal(t, int64(expectValue), middlewareCounter)
  449. }
  450. func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo) {
  451. for _, gotRoute := range gotRoutes {
  452. if gotRoute.Path == wantRoute.Path && gotRoute.Method == wantRoute.Method {
  453. assert.Regexp(t, wantRoute.Handler, gotRoute.Handler)
  454. return
  455. }
  456. }
  457. t.Errorf("route not found: %v", wantRoute)
  458. }
  459. func handlerTest1(c *Context) {}
  460. func handlerTest2(c *Context) {}