go.sdls.io/sin@v0.0.9/pkg/sin/routes_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 sin 6 7 import ( 8 "net/http" 9 "net/http/httptest" 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 ) 14 15 type header struct { 16 Key string 17 Value string 18 } 19 20 func performRequest(r http.Handler, method, path string, headers ...header) *httptest.ResponseRecorder { 21 req := httptest.NewRequest(method, path, nil) 22 for _, h := range headers { 23 req.Header.Add(h.Key, h.Value) 24 } 25 w := httptest.NewRecorder() 26 r.ServeHTTP(w, req) 27 return w 28 } 29 30 func testRouteOK(method string, t *testing.T) { 31 passed := false 32 passedAny := false 33 r := New() 34 r.Any("/test2", func(c *Context) { 35 passedAny = true 36 }) 37 r.Handle(method, "/test", func(c *Context) { 38 passed = true 39 }) 40 41 w := performRequest(r, method, "/test") 42 assert.True(t, passed) 43 assert.Equal(t, http.StatusOK, w.Code) 44 45 performRequest(r, method, "/test2") 46 assert.True(t, passedAny) 47 } 48 49 // TestSingleRouteOK tests that POST route is correctly invoked. 50 func testRouteNotOK(method string, t *testing.T) { 51 passed := false 52 router := New() 53 router.Handle(method, "/test_2", func(c *Context) { 54 passed = true 55 }) 56 57 w := performRequest(router, method, "/test") 58 59 assert.False(t, passed) 60 assert.Equal(t, http.StatusNotFound, w.Code) 61 } 62 63 // TestSingleRouteOK tests that POST route is correctly invoked. 64 func testRouteNotOK2(method string, t *testing.T) { 65 passed := false 66 router := New() 67 router.HandleMethodNotAllowed = true 68 var methodRoute string 69 if method == http.MethodPost { 70 methodRoute = http.MethodGet 71 } else { 72 methodRoute = http.MethodPost 73 } 74 router.Handle(methodRoute, "/test", func(c *Context) { 75 passed = true 76 }) 77 78 w := performRequest(router, method, "/test") 79 80 assert.False(t, passed) 81 assert.Equal(t, http.StatusMethodNotAllowed, w.Code) 82 } 83 84 func TestRouterMethod(t *testing.T) { 85 router := New() 86 router.PUT("/hey2", func(c *Context) { 87 c.String(http.StatusOK, "sup2") 88 }) 89 90 router.PUT("/hey", func(c *Context) { 91 c.String(http.StatusOK, "called") 92 }) 93 94 router.PUT("/hey3", func(c *Context) { 95 c.String(http.StatusOK, "sup3") 96 }) 97 98 w := performRequest(router, http.MethodPut, "/hey") 99 100 assert.Equal(t, http.StatusOK, w.Code) 101 assert.Equal(t, "called", w.Body.String()) 102 } 103 104 func TestRouterGroupRouteOK(t *testing.T) { 105 testRouteOK(http.MethodGet, t) 106 testRouteOK(http.MethodPost, t) 107 testRouteOK(http.MethodPut, t) 108 testRouteOK(http.MethodPatch, t) 109 testRouteOK(http.MethodHead, t) 110 testRouteOK(http.MethodOptions, t) 111 testRouteOK(http.MethodDelete, t) 112 testRouteOK(http.MethodConnect, t) 113 testRouteOK(http.MethodTrace, t) 114 } 115 116 func TestRouteNotOK(t *testing.T) { 117 testRouteNotOK(http.MethodGet, t) 118 testRouteNotOK(http.MethodPost, t) 119 testRouteNotOK(http.MethodPut, t) 120 testRouteNotOK(http.MethodPatch, t) 121 testRouteNotOK(http.MethodHead, t) 122 testRouteNotOK(http.MethodOptions, t) 123 testRouteNotOK(http.MethodDelete, t) 124 testRouteNotOK(http.MethodConnect, t) 125 testRouteNotOK(http.MethodTrace, t) 126 } 127 128 func TestRouteNotOK2(t *testing.T) { 129 testRouteNotOK2(http.MethodGet, t) 130 testRouteNotOK2(http.MethodPost, t) 131 testRouteNotOK2(http.MethodPut, t) 132 testRouteNotOK2(http.MethodPatch, t) 133 testRouteNotOK2(http.MethodHead, t) 134 testRouteNotOK2(http.MethodOptions, t) 135 testRouteNotOK2(http.MethodDelete, t) 136 testRouteNotOK2(http.MethodConnect, t) 137 testRouteNotOK2(http.MethodTrace, t) 138 } 139 140 // TestContextParamsGet tests that a parameter can be parsed from the URL. 141 func TestRouteParamsByName(t *testing.T) { 142 name := "" 143 lastName := "" 144 wild := "" 145 router := New() 146 router.GET("/test/:name/:last_name/*wild", func(c *Context) { 147 name = c.Params.ByName("name") 148 lastName = c.Params.ByName("last_name") 149 var ok bool 150 wild, ok = c.Params.Get("wild") 151 152 assert.True(t, ok) 153 assert.Equal(t, name, c.Param("name")) 154 assert.Equal(t, lastName, c.Param("last_name")) 155 156 assert.Empty(t, c.Param("wtf")) 157 assert.Empty(t, c.Params.ByName("wtf")) 158 159 wtf, ok := c.Params.Get("wtf") 160 assert.Empty(t, wtf) 161 assert.False(t, ok) 162 }) 163 164 w := performRequest(router, http.MethodGet, "/test/john/smith/is/super/great") 165 166 assert.Equal(t, http.StatusOK, w.Code) 167 assert.Equal(t, "john", name) 168 assert.Equal(t, "smith", lastName) 169 assert.Equal(t, "/is/super/great", wild) 170 } 171 172 func TestRouteNotAllowedEnabled(t *testing.T) { 173 router := New() 174 router.HandleMethodNotAllowed = true 175 router.POST("/path", func(c *Context) {}) 176 w := performRequest(router, http.MethodGet, "/path") 177 assert.Equal(t, http.StatusMethodNotAllowed, w.Code) 178 179 router.NoMethod(func(c *Context) { 180 c.String(http.StatusTeapot, "responseText") 181 }) 182 w = performRequest(router, http.MethodGet, "/path") 183 assert.Equal(t, "responseText", w.Body.String()) 184 assert.Equal(t, http.StatusTeapot, w.Code) 185 } 186 187 func TestRouteNotAllowedEnabled2(t *testing.T) { 188 router := New() 189 router.HandleMethodNotAllowed = true 190 // add one methodTree to trees 191 router.addRoute(http.MethodPost, "/", HandlersChain{func(_ *Context) {}}) 192 router.GET("/path2", func(c *Context) {}) 193 w := performRequest(router, http.MethodPost, "/path2") 194 assert.Equal(t, http.StatusMethodNotAllowed, w.Code) 195 } 196 197 func TestRouteNotAllowedDisabled(t *testing.T) { 198 router := New() 199 router.HandleMethodNotAllowed = false 200 router.POST("/path", func(c *Context) {}) 201 w := performRequest(router, http.MethodGet, "/path") 202 assert.Equal(t, http.StatusNotFound, w.Code) 203 204 router.NoMethod(func(c *Context) { 205 c.String(http.StatusTeapot, "responseText") 206 }) 207 w = performRequest(router, http.MethodGet, "/path") 208 assert.Equal(t, "404 page not found", w.Body.String()) 209 assert.Equal(t, http.StatusNotFound, w.Code) 210 } 211 212 func TestRouteRawPath(t *testing.T) { 213 route := New() 214 route.UseRawPath = true 215 216 route.POST("/project/:name/build/:num", func(c *Context) { 217 name := c.Params.ByName("name") 218 num := c.Params.ByName("num") 219 220 assert.Equal(t, name, c.Param("name")) 221 assert.Equal(t, num, c.Param("num")) 222 223 assert.Equal(t, "Some/Other/Project", name) 224 assert.Equal(t, "222", num) 225 }) 226 227 w := performRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/222") 228 assert.Equal(t, http.StatusOK, w.Code) 229 } 230 231 func TestRouteRawPathNoUnescape(t *testing.T) { 232 route := New() 233 route.UseRawPath = true 234 route.UnescapePathValues = false 235 236 route.POST("/project/:name/build/:num", func(c *Context) { 237 name := c.Params.ByName("name") 238 num := c.Params.ByName("num") 239 240 assert.Equal(t, name, c.Param("name")) 241 assert.Equal(t, num, c.Param("num")) 242 243 assert.Equal(t, "Some%2FOther%2FProject", name) 244 assert.Equal(t, "333", num) 245 }) 246 247 w := performRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/333") 248 assert.Equal(t, http.StatusOK, w.Code) 249 } 250 251 func TestRouteServeErrorWithWriteHeader(t *testing.T) { 252 route := New() 253 route.Use(func(c *Context) { 254 c.Status(421) 255 c.Next() 256 }) 257 258 w := performRequest(route, http.MethodGet, "/NotFound") 259 assert.Equal(t, 421, w.Code) 260 assert.Equal(t, 0, w.Body.Len()) 261 } 262 263 func TestRouteContextHoldsFullPath(t *testing.T) { 264 router := New() 265 266 // Test routes 267 routes := []string{ 268 "/simple", 269 "/project/:name", 270 "/", 271 "/news/home", 272 "/news", 273 "/simple-two/one", 274 "/simple-two/one-two", 275 "/project/:name/build/*params", 276 "/project/:name/bui", 277 "/user/:id/status", 278 "/user/:id", 279 "/user/:id/profile", 280 } 281 282 for _, route := range routes { 283 actualRoute := route 284 router.GET(route, func(c *Context) { 285 // For each defined route context should contain its full path 286 assert.Equal(t, actualRoute, c.FullPath()) 287 c.AbortWithStatus(http.StatusOK) 288 }) 289 } 290 291 for _, route := range routes { 292 w := performRequest(router, http.MethodGet, route) 293 assert.Equal(t, http.StatusOK, w.Code) 294 } 295 296 // Test not found 297 router.Use(func(c *Context) { 298 // For not found routes full path is empty 299 assert.Equal(t, "", c.FullPath()) 300 }) 301 302 w := performRequest(router, http.MethodGet, "/not-found") 303 assert.Equal(t, http.StatusNotFound, w.Code) 304 }