/mux/mux_test.go

https://code.google.com/p/gorilla/ · Go · 417 lines · 328 code · 48 blank · 41 comment · 47 complexity · 5e1018b74f927c9df2df1bba8a226e36 MD5 · raw file

  1. // Copyright 2012 The Gorilla Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package mux
  5. import (
  6. "fmt"
  7. "net/http"
  8. "testing"
  9. )
  10. func TestRoute(t *testing.T) {
  11. var route *Route
  12. var request *http.Request
  13. var vars map[string]string
  14. var host, path, url string
  15. // Setup an id so we can see which test failed. :)
  16. var idValue int
  17. id := func() int {
  18. idValue++
  19. return idValue
  20. }
  21. // Host -------------------------------------------------------------------
  22. route = new(Route).Host("aaa.bbb.ccc")
  23. request, _ = http.NewRequest("GET", "http://aaa.bbb.ccc/111/222/333", nil)
  24. vars = map[string]string{}
  25. host = "aaa.bbb.ccc"
  26. path = ""
  27. url = host + path
  28. testRoute(t, id(), true, route, request, vars, host, path, url)
  29. // Non-match for the same config.
  30. request, _ = http.NewRequest("GET", "http://aaa.222.ccc/111/222/333", nil)
  31. testRoute(t, id(), false, route, request, vars, host, path, url)
  32. route = new(Route).Host("aaa.{v1:[a-z]{3}}.ccc")
  33. request, _ = http.NewRequest("GET", "http://aaa.bbb.ccc/111/222/333", nil)
  34. vars = map[string]string{"v1": "bbb"}
  35. host = "aaa.bbb.ccc"
  36. path = ""
  37. url = host + path
  38. testRoute(t, id(), true, route, request, vars, host, path, url)
  39. // Non-match for the same config.
  40. request, _ = http.NewRequest("GET", "http://aaa.222.ccc/111/222/333", nil)
  41. testRoute(t, id(), false, route, request, vars, host, path, url)
  42. route = new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}")
  43. request, _ = http.NewRequest("GET", "http://aaa.bbb.ccc/111/222/333", nil)
  44. vars = map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc"}
  45. host = "aaa.bbb.ccc"
  46. path = ""
  47. url = host + path
  48. testRoute(t, id(), true, route, request, vars, host, path, url)
  49. // Non-match for the same config.
  50. request, _ = http.NewRequest("GET", "http://aaa.222.ccc/111/222/333", nil)
  51. testRoute(t, id(), false, route, request, vars, host, path, url)
  52. // Path -------------------------------------------------------------------
  53. route = new(Route).Path("/111/222/333")
  54. request, _ = http.NewRequest("GET", "http://localhost/111/222/333", nil)
  55. vars = map[string]string{}
  56. host = ""
  57. path = "/111/222/333"
  58. url = host + path
  59. testRoute(t, id(), true, route, request, vars, host, path, url)
  60. // Non-match for the same config.
  61. request, _ = http.NewRequest("GET", "http://localhost/1/2/3", nil)
  62. testRoute(t, id(), false, route, request, vars, host, path, url)
  63. route = new(Route).Path("/111/{v1:[0-9]{3}}/333")
  64. request, _ = http.NewRequest("GET", "http://localhost/111/222/333", nil)
  65. vars = map[string]string{"v1": "222"}
  66. host = ""
  67. path = "/111/222/333"
  68. url = host + path
  69. testRoute(t, id(), true, route, request, vars, host, path, url)
  70. // Non-match for the same config.
  71. request, _ = http.NewRequest("GET", "http://localhost/111/aaa/333", nil)
  72. testRoute(t, id(), false, route, request, vars, host, path, url)
  73. route = new(Route).Path("/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}")
  74. request, _ = http.NewRequest("GET", "http://localhost/111/222/333", nil)
  75. vars = map[string]string{"v1": "111", "v2": "222", "v3": "333"}
  76. host = ""
  77. path = "/111/222/333"
  78. url = host + path
  79. testRoute(t, id(), true, route, request, vars, host, path, url)
  80. // Non-match for the same config.
  81. request, _ = http.NewRequest("GET", "http://localhost/111/aaa/333", nil)
  82. testRoute(t, id(), false, route, request, vars, host, path, url)
  83. // PathPrefix -------------------------------------------------------------
  84. route = new(Route).PathPrefix("/111")
  85. request, _ = http.NewRequest("GET", "http://localhost/111/222/333", nil)
  86. vars = map[string]string{}
  87. host = ""
  88. path = "/111"
  89. url = host + path
  90. testRoute(t, id(), true, route, request, vars, host, path, url)
  91. // Non-match for the same config.
  92. request, _ = http.NewRequest("GET", "http://localhost/1/2/3", nil)
  93. testRoute(t, id(), false, route, request, vars, host, path, url)
  94. route = new(Route).PathPrefix("/111/{v1:[0-9]{3}}")
  95. request, _ = http.NewRequest("GET", "http://localhost/111/222/333", nil)
  96. vars = map[string]string{"v1": "222"}
  97. host = ""
  98. path = "/111/222"
  99. url = host + path
  100. testRoute(t, id(), true, route, request, vars, host, path, url)
  101. // Non-match for the same config.
  102. request, _ = http.NewRequest("GET", "http://localhost/111/aaa/333", nil)
  103. testRoute(t, id(), false, route, request, vars, host, path, url)
  104. route = new(Route).PathPrefix("/{v1:[0-9]{3}}/{v2:[0-9]{3}}")
  105. request, _ = http.NewRequest("GET", "http://localhost/111/222/333", nil)
  106. vars = map[string]string{"v1": "111", "v2": "222"}
  107. host = ""
  108. path = "/111/222"
  109. url = host + path
  110. testRoute(t, id(), true, route, request, vars, host, path, url)
  111. // Non-match for the same config.
  112. request, _ = http.NewRequest("GET", "http://localhost/111/aaa/333", nil)
  113. testRoute(t, id(), false, route, request, vars, host, path, url)
  114. // Host + Path ------------------------------------------------------------
  115. route = new(Route).Host("aaa.bbb.ccc").Path("/111/222/333")
  116. request, _ = http.NewRequest("GET", "http://aaa.bbb.ccc/111/222/333", nil)
  117. vars = map[string]string{}
  118. host = ""
  119. path = ""
  120. url = host + path
  121. testRoute(t, id(), true, route, request, vars, host, path, url)
  122. // Non-match for the same config.
  123. request, _ = http.NewRequest("GET", "http://aaa.222.ccc/111/222/333", nil)
  124. testRoute(t, id(), false, route, request, vars, host, path, url)
  125. route = new(Route).Host("aaa.{v1:[a-z]{3}}.ccc").Path("/111/{v2:[0-9]{3}}/333")
  126. request, _ = http.NewRequest("GET", "http://aaa.bbb.ccc/111/222/333", nil)
  127. vars = map[string]string{"v1": "bbb", "v2": "222"}
  128. host = "aaa.bbb.ccc"
  129. path = "/111/222/333"
  130. url = host + path
  131. testRoute(t, id(), true, route, request, vars, host, path, url)
  132. // Non-match for the same config.
  133. request, _ = http.NewRequest("GET", "http://aaa.222.ccc/111/222/333", nil)
  134. testRoute(t, id(), false, route, request, vars, host, path, url)
  135. route = new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}").Path("/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}")
  136. request, _ = http.NewRequest("GET", "http://aaa.bbb.ccc/111/222/333", nil)
  137. vars = map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc", "v4": "111", "v5": "222", "v6": "333"}
  138. host = "aaa.bbb.ccc"
  139. path = "/111/222/333"
  140. url = host + path
  141. testRoute(t, id(), true, route, request, vars, host, path, url)
  142. // Non-match for the same config.
  143. request, _ = http.NewRequest("GET", "http://aaa.222.ccc/111/222/333", nil)
  144. testRoute(t, id(), false, route, request, vars, host, path, url)
  145. // Headers ----------------------------------------------------------------
  146. route = new(Route).Headers("foo", "bar", "baz", "ding")
  147. request, _ = http.NewRequest("GET", "http://localhost", nil)
  148. request.Header.Add("foo", "bar")
  149. request.Header.Add("baz", "ding")
  150. vars = map[string]string{}
  151. host = ""
  152. path = ""
  153. url = host + path
  154. testRoute(t, id(), true, route, request, vars, host, path, url)
  155. // Non-match for the same config.
  156. request, _ = http.NewRequest("GET", "http://localhost", nil)
  157. request.Header.Add("foo", "bar")
  158. request.Header.Add("baz", "dong")
  159. testRoute(t, id(), false, route, request, vars, host, path, url)
  160. // Methods ----------------------------------------------------------------
  161. route = new(Route).Methods("GET", "POST")
  162. request, _ = http.NewRequest("GET", "http://localhost", nil)
  163. vars = map[string]string{}
  164. host = ""
  165. path = ""
  166. url = host + path
  167. testRoute(t, id(), true, route, request, vars, host, path, url)
  168. request, _ = http.NewRequest("POST", "http://localhost", nil)
  169. testRoute(t, id(), true, route, request, vars, host, path, url)
  170. // Non-match for the same config.
  171. request, _ = http.NewRequest("PUT", "http://localhost", nil)
  172. testRoute(t, id(), false, route, request, vars, host, path, url)
  173. // Queries ----------------------------------------------------------------
  174. route = new(Route).Queries("foo", "bar", "baz", "ding")
  175. request, _ = http.NewRequest("GET", "http://localhost?foo=bar&baz=ding", nil)
  176. vars = map[string]string{}
  177. host = ""
  178. path = ""
  179. url = host + path
  180. testRoute(t, id(), true, route, request, vars, host, path, url)
  181. // Non-match for the same config.
  182. request, _ = http.NewRequest("GET", "http://localhost?foo=bar&baz=dong", nil)
  183. testRoute(t, id(), false, route, request, vars, host, path, url)
  184. // Schemes ----------------------------------------------------------------
  185. route = new(Route).Schemes("https", "ftp")
  186. request, _ = http.NewRequest("GET", "https://localhost", nil)
  187. vars = map[string]string{}
  188. host = ""
  189. path = ""
  190. url = host + path
  191. testRoute(t, id(), true, route, request, vars, host, path, url)
  192. request, _ = http.NewRequest("GET", "ftp://localhost", nil)
  193. testRoute(t, id(), true, route, request, vars, host, path, url)
  194. // Non-match for the same config.
  195. request, _ = http.NewRequest("GET", "http://localhost", nil)
  196. testRoute(t, id(), false, route, request, vars, host, path, url)
  197. // Custom -----------------------------------------------------------------
  198. m := func(r *http.Request, m *RouteMatch) bool {
  199. if r.URL.Host == "aaa.bbb.ccc" {
  200. return true
  201. }
  202. return false
  203. }
  204. route = new(Route).MatcherFunc(m)
  205. request, _ = http.NewRequest("GET", "http://aaa.bbb.ccc", nil)
  206. vars = map[string]string{}
  207. host = ""
  208. path = ""
  209. url = host + path
  210. testRoute(t, id(), true, route, request, vars, host, path, url)
  211. // Non-match for the same config.
  212. request, _ = http.NewRequest("GET", "http://aaa.ccc.bbb", nil)
  213. testRoute(t, id(), false, route, request, vars, host, path, url)
  214. }
  215. func TestSubRouter(t *testing.T) {
  216. var route *Route
  217. var request *http.Request
  218. var vars map[string]string
  219. var host, path, url string
  220. subrouter := new(Route).Host("{v1:[a-z]+}.google.com").Subrouter()
  221. // Setup an id so we can see which test failed. :)
  222. var idValue int
  223. id := func() int {
  224. idValue++
  225. return idValue
  226. }
  227. // ------------------------------------------------------------------------
  228. route = subrouter.Path("/{v2:[a-z]+}")
  229. request, _ = http.NewRequest("GET", "http://aaa.google.com/bbb", nil)
  230. vars = map[string]string{"v1": "aaa", "v2": "bbb"}
  231. host = "aaa.google.com"
  232. path = "/bbb"
  233. url = host + path
  234. testRoute(t, id(), true, route, request, vars, host, path, url)
  235. // Non-match for the same config.
  236. request, _ = http.NewRequest("GET", "http://111.google.com/111", nil)
  237. testRoute(t, id(), false, route, request, vars, host, path, url)
  238. // ------------------------------------------------------------------------
  239. subrouter = new(Route).PathPrefix("/foo/{v1}").Subrouter()
  240. route = subrouter.Path("/baz/{v2}")
  241. request, _ = http.NewRequest("GET", "http://localhost/foo/bar/baz/ding", nil)
  242. vars = map[string]string{"v1": "bar", "v2": "ding"}
  243. host = ""
  244. path = "/foo/bar/baz/ding"
  245. url = host + path
  246. testRoute(t, id(), true, route, request, vars, host, path, url)
  247. // Non-match for the same config.
  248. request, _ = http.NewRequest("GET", "http://localhost/foo/bar", nil)
  249. testRoute(t, id(), false, route, request, vars, host, path, url)
  250. }
  251. func TestNamedRoutes(t *testing.T) {
  252. r1 := NewRouter()
  253. r1.NewRoute().Name("a")
  254. r1.NewRoute().Name("b")
  255. r1.NewRoute().Name("c")
  256. r2 := r1.NewRoute().Subrouter()
  257. r2.NewRoute().Name("d")
  258. r2.NewRoute().Name("e")
  259. r2.NewRoute().Name("f")
  260. r3 := r2.NewRoute().Subrouter()
  261. r3.NewRoute().Name("g")
  262. r3.NewRoute().Name("h")
  263. r3.NewRoute().Name("i")
  264. if r1.namedRoutes == nil || len(r1.namedRoutes) != 9 {
  265. t.Errorf("Expected 9 named routes, got %v", r1.namedRoutes)
  266. } else if r1.Get("i") == nil {
  267. t.Errorf("Subroute name not registered")
  268. }
  269. }
  270. // ----------------------------------------------------------------------------
  271. // Helpers
  272. // ----------------------------------------------------------------------------
  273. func getRouteTemplate(route *Route) string {
  274. host, path := "none", "none"
  275. if route.regexp != nil {
  276. if route.regexp.host != nil {
  277. host = route.regexp.host.template
  278. }
  279. if route.regexp.path != nil {
  280. path = route.regexp.path.template
  281. }
  282. }
  283. return fmt.Sprintf("Host: %v, Path: %v", host, path)
  284. }
  285. func testRoute(t *testing.T, id int, shouldMatch bool, route *Route,
  286. request *http.Request, vars map[string]string, host, path, url string) {
  287. var match RouteMatch
  288. ok := route.Match(request, &match)
  289. if ok != shouldMatch {
  290. msg := "Should match"
  291. if !shouldMatch {
  292. msg = "Should not match"
  293. }
  294. t.Errorf("(%v) %v:\nRoute: %#v\nRequest: %#v\nVars: %v\n", id, msg, route, request, vars)
  295. return
  296. }
  297. if shouldMatch {
  298. if vars != nil && !stringMapEqual(vars, match.Vars) {
  299. t.Errorf("(%v) Vars not equal: expected %v, got %v", id, vars, match.Vars)
  300. return
  301. }
  302. if host != "" {
  303. u, _ := route.URLHost(mapToPairs(match.Vars)...)
  304. if host != u.Host {
  305. t.Errorf("(%v) URLHost not equal: expected %v, got %v -- %v", id, host, u.Host, getRouteTemplate(route))
  306. return
  307. }
  308. }
  309. if path != "" {
  310. u, _ := route.URLPath(mapToPairs(match.Vars)...)
  311. if path != u.Path {
  312. t.Errorf("(%v) URLPath not equal: expected %v, got %v -- %v", id, path, u.Path, getRouteTemplate(route))
  313. return
  314. }
  315. }
  316. if url != "" {
  317. u, _ := route.URL(mapToPairs(match.Vars)...)
  318. if url != u.Host+u.Path {
  319. t.Errorf("(%v) URL not equal: expected %v, got %v -- %v", id, url, u.Host+u.Path, getRouteTemplate(route))
  320. return
  321. }
  322. }
  323. }
  324. }
  325. func TestStrictSlash(t *testing.T) {
  326. var r *Router
  327. var req *http.Request
  328. var route *Route
  329. var match *RouteMatch
  330. var matched bool
  331. // StrictSlash should be ignored for path prefix.
  332. // So we register a route ending in slash but it doesn't attempt to add
  333. // the slash for a path not ending in slash.
  334. r = NewRouter()
  335. r.StrictSlash(true)
  336. route = r.NewRoute().PathPrefix("/static/")
  337. req, _ = http.NewRequest("GET", "http://localhost/static/logo.png", nil)
  338. match = new(RouteMatch)
  339. matched = r.Match(req, match)
  340. if !matched {
  341. t.Errorf("Should match request %q -- %v", req.URL.Path, getRouteTemplate(route))
  342. }
  343. if match.Handler != nil {
  344. t.Errorf("Should not redirect")
  345. }
  346. }
  347. func mapToPairs(m map[string]string) []string {
  348. var i int
  349. p := make([]string, len(m)*2)
  350. for k, v := range m {
  351. p[i] = k
  352. p[i+1] = v
  353. i += 2
  354. }
  355. return p
  356. }
  357. func stringMapEqual(m1, m2 map[string]string) bool {
  358. nil1 := m1 == nil
  359. nil2 := m2 == nil
  360. if nil1 != nil2 || len(m1) != len(m2) {
  361. return false
  362. }
  363. for k, v := range m1 {
  364. if v != m2[k] {
  365. return false
  366. }
  367. }
  368. return true
  369. }