gin/routes_test.go

490 lines
14 KiB
Go
Raw Normal View History

2015-04-08 00:58:35 +00:00
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
2015-05-05 14:37:33 +00:00
"fmt"
2015-04-08 00:58:35 +00:00
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
2015-04-08 00:58:35 +00:00
"testing"
"github.com/stretchr/testify/assert"
)
func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
req, _ := http.NewRequest(method, path, nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
return w
}
func testRouteOK(method string, t *testing.T) {
passed := false
2015-05-19 21:00:55 +00:00
passedAny := false
2015-04-08 00:58:35 +00:00
r := New()
2015-05-19 21:00:55 +00:00
r.Any("/test2", func(c *Context) {
passedAny = true
})
2015-05-19 21:22:35 +00:00
r.Handle(method, "/test", func(c *Context) {
2015-04-08 00:58:35 +00:00
passed = true
2015-05-19 21:22:35 +00:00
})
2015-05-18 18:50:46 +00:00
2015-04-08 00:58:35 +00:00
w := performRequest(r, method, "/test")
assert.True(t, passed)
assert.Equal(t, http.StatusOK, w.Code)
2015-05-19 21:00:55 +00:00
performRequest(r, method, "/test2")
assert.True(t, passedAny)
2015-04-08 00:58:35 +00:00
}
// TestSingleRouteOK tests that POST route is correctly invoked.
func testRouteNotOK(method string, t *testing.T) {
passed := false
router := New()
2015-05-19 21:22:35 +00:00
router.Handle(method, "/test_2", func(c *Context) {
2015-04-08 00:58:35 +00:00
passed = true
2015-05-19 21:22:35 +00:00
})
2015-04-08 00:58:35 +00:00
w := performRequest(router, method, "/test")
assert.False(t, passed)
assert.Equal(t, http.StatusNotFound, w.Code)
2015-04-08 00:58:35 +00:00
}
// TestSingleRouteOK tests that POST route is correctly invoked.
func testRouteNotOK2(method string, t *testing.T) {
passed := false
router := New()
router.HandleMethodNotAllowed = true
2015-04-08 00:58:35 +00:00
var methodRoute string
if method == "POST" {
methodRoute = "GET"
} else {
methodRoute = "POST"
}
2015-05-19 21:22:35 +00:00
router.Handle(methodRoute, "/test", func(c *Context) {
2015-04-08 00:58:35 +00:00
passed = true
2015-05-19 21:22:35 +00:00
})
2015-04-08 00:58:35 +00:00
w := performRequest(router, method, "/test")
assert.False(t, passed)
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
2015-04-08 00:58:35 +00:00
}
2015-06-03 23:54:36 +00:00
func TestRouterMethod(t *testing.T) {
router := New()
router.PUT("/hey2", func(c *Context) {
c.String(http.StatusOK, "sup2")
2015-06-03 23:54:36 +00:00
})
router.PUT("/hey", func(c *Context) {
c.String(http.StatusOK, "called")
2015-06-03 23:54:36 +00:00
})
router.PUT("/hey3", func(c *Context) {
c.String(http.StatusOK, "sup3")
2015-06-03 23:54:36 +00:00
})
w := performRequest(router, "PUT", "/hey")
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "called", w.Body.String())
2015-06-03 23:54:36 +00:00
}
2015-04-08 00:58:35 +00:00
func TestRouterGroupRouteOK(t *testing.T) {
testRouteOK("GET", t)
2015-04-08 00:58:35 +00:00
testRouteOK("POST", t)
testRouteOK("PUT", t)
testRouteOK("PATCH", t)
2015-04-08 00:58:35 +00:00
testRouteOK("HEAD", t)
testRouteOK("OPTIONS", t)
testRouteOK("DELETE", t)
testRouteOK("CONNECT", t)
testRouteOK("TRACE", t)
2015-04-08 00:58:35 +00:00
}
func TestRouteNotOK(t *testing.T) {
testRouteNotOK("GET", t)
2015-04-08 00:58:35 +00:00
testRouteNotOK("POST", t)
testRouteNotOK("PUT", t)
testRouteNotOK("PATCH", t)
2015-04-08 00:58:35 +00:00
testRouteNotOK("HEAD", t)
testRouteNotOK("OPTIONS", t)
testRouteNotOK("DELETE", t)
testRouteNotOK("CONNECT", t)
testRouteNotOK("TRACE", t)
2015-04-08 00:58:35 +00:00
}
func TestRouteNotOK2(t *testing.T) {
testRouteNotOK2("GET", t)
2015-04-08 00:58:35 +00:00
testRouteNotOK2("POST", t)
testRouteNotOK2("PUT", t)
testRouteNotOK2("PATCH", t)
2015-04-08 00:58:35 +00:00
testRouteNotOK2("HEAD", t)
testRouteNotOK2("OPTIONS", t)
testRouteNotOK2("DELETE", t)
testRouteNotOK2("CONNECT", t)
testRouteNotOK2("TRACE", t)
2015-04-08 00:58:35 +00:00
}
func TestRouteRedirectTrailingSlash(t *testing.T) {
router := New()
router.RedirectFixedPath = false
router.RedirectTrailingSlash = true
router.GET("/path", func(c *Context) {})
router.GET("/path2/", func(c *Context) {})
router.POST("/path3", func(c *Context) {})
router.PUT("/path4/", func(c *Context) {})
w := performRequest(router, "GET", "/path/")
assert.Equal(t, "/path", w.Header().Get("Location"))
assert.Equal(t, http.StatusMovedPermanently, w.Code)
w = performRequest(router, "GET", "/path2")
assert.Equal(t, "/path2/", w.Header().Get("Location"))
assert.Equal(t, http.StatusMovedPermanently, w.Code)
w = performRequest(router, "POST", "/path3/")
assert.Equal(t, "/path3", w.Header().Get("Location"))
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
w = performRequest(router, "PUT", "/path4")
assert.Equal(t, "/path4/", w.Header().Get("Location"))
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
w = performRequest(router, "GET", "/path")
assert.Equal(t, http.StatusOK, w.Code)
w = performRequest(router, "GET", "/path2/")
assert.Equal(t, http.StatusOK, w.Code)
w = performRequest(router, "POST", "/path3")
assert.Equal(t, http.StatusOK, w.Code)
w = performRequest(router, "PUT", "/path4/")
assert.Equal(t, http.StatusOK, w.Code)
router.RedirectTrailingSlash = false
w = performRequest(router, "GET", "/path/")
assert.Equal(t, http.StatusNotFound, w.Code)
w = performRequest(router, "GET", "/path2")
assert.Equal(t, http.StatusNotFound, w.Code)
w = performRequest(router, "POST", "/path3/")
assert.Equal(t, http.StatusNotFound, w.Code)
w = performRequest(router, "PUT", "/path4")
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestRouteRedirectFixedPath(t *testing.T) {
router := New()
router.RedirectFixedPath = true
router.RedirectTrailingSlash = false
router.GET("/path", func(c *Context) {})
router.GET("/Path2", func(c *Context) {})
router.POST("/PATH3", func(c *Context) {})
router.POST("/Path4/", func(c *Context) {})
w := performRequest(router, "GET", "/PATH")
assert.Equal(t, "/path", w.Header().Get("Location"))
assert.Equal(t, http.StatusMovedPermanently, w.Code)
w = performRequest(router, "GET", "/path2")
assert.Equal(t, "/Path2", w.Header().Get("Location"))
assert.Equal(t, http.StatusMovedPermanently, w.Code)
w = performRequest(router, "POST", "/path3")
assert.Equal(t, "/PATH3", w.Header().Get("Location"))
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
w = performRequest(router, "POST", "/path4")
assert.Equal(t, "/Path4/", w.Header().Get("Location"))
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
}
// TestContextParamsGet tests that a parameter can be parsed from the URL.
func TestRouteParamsByName(t *testing.T) {
name := ""
lastName := ""
2015-05-05 14:37:33 +00:00
wild := ""
router := New()
2015-05-05 14:37:33 +00:00
router.GET("/test/:name/:last_name/*wild", func(c *Context) {
name = c.Params.ByName("name")
lastName = c.Params.ByName("last_name")
2015-05-26 15:49:25 +00:00
var ok bool
wild, ok = c.Params.Get("wild")
2015-05-05 14:37:33 +00:00
2015-05-26 15:49:25 +00:00
assert.True(t, ok)
assert.Equal(t, name, c.Param("name"))
2015-05-26 10:11:59 +00:00
assert.Equal(t, name, c.Param("name"))
assert.Equal(t, lastName, c.Param("last_name"))
2015-05-26 15:49:25 +00:00
assert.Empty(t, c.Param("wtf"))
assert.Empty(t, c.Params.ByName("wtf"))
wtf, ok := c.Params.Get("wtf")
assert.Empty(t, wtf)
assert.False(t, ok)
})
2015-05-18 18:50:46 +00:00
2015-05-05 14:37:33 +00:00
w := performRequest(router, "GET", "/test/john/smith/is/super/great")
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "john", name)
assert.Equal(t, "smith", lastName)
assert.Equal(t, "/is/super/great", wild)
}
2015-04-08 00:58:35 +00:00
// TestHandleStaticFile - ensure the static file handles properly
func TestRouteStaticFile(t *testing.T) {
2015-04-08 00:58:35 +00:00
// SETUP file
testRoot, _ := os.Getwd()
f, err := ioutil.TempFile(testRoot, "")
if err != nil {
t.Error(err)
}
defer os.Remove(f.Name())
2019-01-18 01:32:53 +00:00
_, err = f.WriteString("Gin Web Framework")
assert.NoError(t, err)
2015-04-08 00:58:35 +00:00
f.Close()
dir, filename := filepath.Split(f.Name())
2015-04-08 00:58:35 +00:00
// SETUP gin
2015-05-18 18:50:46 +00:00
router := New()
router.Static("/using_static", dir)
router.StaticFile("/result", f.Name())
2015-04-08 00:58:35 +00:00
w := performRequest(router, "GET", "/using_static/"+filename)
w2 := performRequest(router, "GET", "/result")
2015-04-08 00:58:35 +00:00
assert.Equal(t, w, w2)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "Gin Web Framework", w.Body.String())
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
w3 := performRequest(router, "HEAD", "/using_static/"+filename)
w4 := performRequest(router, "HEAD", "/result")
assert.Equal(t, w3, w4)
assert.Equal(t, http.StatusOK, w3.Code)
2015-04-08 00:58:35 +00:00
}
// TestHandleStaticDir - ensure the root/sub dir handles properly
func TestRouteStaticListingDir(t *testing.T) {
2015-05-18 18:50:46 +00:00
router := New()
router.StaticFS("/", Dir("./", true))
2015-04-08 00:58:35 +00:00
2015-05-18 18:50:46 +00:00
w := performRequest(router, "GET", "/")
2015-04-08 00:58:35 +00:00
assert.Equal(t, http.StatusOK, w.Code)
2015-05-18 18:50:46 +00:00
assert.Contains(t, w.Body.String(), "gin.go")
assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
2015-04-08 00:58:35 +00:00
}
// TestHandleHeadToDir - ensure the root/sub dir handles properly
func TestRouteStaticNoListing(t *testing.T) {
2015-04-08 00:58:35 +00:00
router := New()
router.Static("/", "./")
w := performRequest(router, "GET", "/")
2015-04-08 00:58:35 +00:00
assert.Equal(t, http.StatusNotFound, w.Code)
assert.NotContains(t, w.Body.String(), "gin.go")
2015-05-18 18:50:46 +00:00
}
func TestRouterMiddlewareAndStatic(t *testing.T) {
router := New()
static := router.Group("/", func(c *Context) {
c.Writer.Header().Add("Last-Modified", "Mon, 02 Jan 2006 15:04:05 MST")
c.Writer.Header().Add("Expires", "Mon, 02 Jan 2006 15:04:05 MST")
c.Writer.Header().Add("X-GIN", "Gin Framework")
})
static.Static("/", "./")
w := performRequest(router, "GET", "/gin.go")
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "package gin")
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
assert.NotEqual(t, w.Header().Get("Last-Modified"), "Mon, 02 Jan 2006 15:04:05 MST")
assert.Equal(t, "Mon, 02 Jan 2006 15:04:05 MST", w.Header().Get("Expires"))
assert.Equal(t, "Gin Framework", w.Header().Get("x-GIN"))
2015-04-08 00:58:35 +00:00
}
2015-05-05 14:37:33 +00:00
func TestRouteNotAllowedEnabled(t *testing.T) {
2015-05-05 14:37:33 +00:00
router := New()
router.HandleMethodNotAllowed = true
2015-05-05 14:37:33 +00:00
router.POST("/path", func(c *Context) {})
w := performRequest(router, "GET", "/path")
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
2015-05-05 14:37:33 +00:00
router.NoMethod(func(c *Context) {
c.String(http.StatusTeapot, "responseText")
})
w = performRequest(router, "GET", "/path")
assert.Equal(t, "responseText", w.Body.String())
assert.Equal(t, http.StatusTeapot, w.Code)
2015-05-05 14:37:33 +00:00
}
func TestRouteNotAllowedEnabled2(t *testing.T) {
router := New()
router.HandleMethodNotAllowed = true
// add one methodTree to trees
router.addRoute("POST", "/", HandlersChain{func(_ *Context) {}})
router.GET("/path2", func(c *Context) {})
w := performRequest(router, "POST", "/path2")
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
}
func TestRouteNotAllowedDisabled(t *testing.T) {
router := New()
router.HandleMethodNotAllowed = false
router.POST("/path", func(c *Context) {})
w := performRequest(router, "GET", "/path")
assert.Equal(t, http.StatusNotFound, w.Code)
router.NoMethod(func(c *Context) {
c.String(http.StatusTeapot, "responseText")
})
w = performRequest(router, "GET", "/path")
assert.Equal(t, "404 page not found", w.Body.String())
assert.Equal(t, http.StatusNotFound, w.Code)
}
2015-05-05 14:37:33 +00:00
func TestRouterNotFound(t *testing.T) {
router := New()
router.RedirectFixedPath = true
2015-05-05 14:37:33 +00:00
router.GET("/path", func(c *Context) {})
router.GET("/dir/", func(c *Context) {})
router.GET("/", func(c *Context) {})
testRoutes := []struct {
route string
code int
location string
2015-05-05 14:37:33 +00:00
}{
{"/path/", http.StatusMovedPermanently, "/path"}, // TSR -/
{"/dir", http.StatusMovedPermanently, "/dir/"}, // TSR +/
{"", http.StatusMovedPermanently, "/"}, // TSR +/
{"/PATH", http.StatusMovedPermanently, "/path"}, // Fixed Case
{"/DIR/", http.StatusMovedPermanently, "/dir/"}, // Fixed Case
{"/PATH/", http.StatusMovedPermanently, "/path"}, // Fixed Case -/
{"/DIR", http.StatusMovedPermanently, "/dir/"}, // Fixed Case +/
{"/../path", http.StatusMovedPermanently, "/path"}, // CleanPath
{"/nope", http.StatusNotFound, ""}, // NotFound
2015-05-05 14:37:33 +00:00
}
for _, tr := range testRoutes {
w := performRequest(router, "GET", tr.route)
assert.Equal(t, tr.code, w.Code)
if w.Code != http.StatusNotFound {
assert.Equal(t, tr.location, fmt.Sprint(w.Header().Get("Location")))
2015-05-05 14:37:33 +00:00
}
}
// Test custom not found handler
var notFound bool
router.NoRoute(func(c *Context) {
c.AbortWithStatus(http.StatusNotFound)
2015-05-05 14:37:33 +00:00
notFound = true
})
w := performRequest(router, "GET", "/nope")
assert.Equal(t, http.StatusNotFound, w.Code)
2015-05-05 14:37:33 +00:00
assert.True(t, notFound)
// Test other method than GET (want 307 instead of 301)
router.PATCH("/path", func(c *Context) {})
w = performRequest(router, "PATCH", "/path/")
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
assert.Equal(t, "map[Location:[/path]]", fmt.Sprint(w.Header()))
2015-05-05 14:37:33 +00:00
// Test special case where no node for the prefix "/" exists
router = New()
router.GET("/a", func(c *Context) {})
w = performRequest(router, "GET", "/")
assert.Equal(t, http.StatusNotFound, w.Code)
2015-05-05 14:37:33 +00:00
}
func TestRouterStaticFSNotFound(t *testing.T) {
router := New()
router.StaticFS("/", http.FileSystem(http.Dir("/thisreallydoesntexist/")))
router.NoRoute(func(c *Context) {
c.String(404, "non existent")
})
w := performRequest(router, "GET", "/nonexistent")
assert.Equal(t, "non existent", w.Body.String())
w = performRequest(router, "HEAD", "/nonexistent")
assert.Equal(t, "non existent", w.Body.String())
}
func TestRouterStaticFSFileNotFound(t *testing.T) {
router := New()
router.StaticFS("/", http.FileSystem(http.Dir(".")))
assert.NotPanics(t, func() {
performRequest(router, "GET", "/nonexistent")
})
}
func TestRouteRawPath(t *testing.T) {
route := New()
route.UseRawPath = true
route.POST("/project/:name/build/:num", func(c *Context) {
name := c.Params.ByName("name")
num := c.Params.ByName("num")
assert.Equal(t, name, c.Param("name"))
assert.Equal(t, num, c.Param("num"))
assert.Equal(t, "Some/Other/Project", name)
assert.Equal(t, "222", num)
})
w := performRequest(route, "POST", "/project/Some%2FOther%2FProject/build/222")
assert.Equal(t, http.StatusOK, w.Code)
}
func TestRouteRawPathNoUnescape(t *testing.T) {
route := New()
route.UseRawPath = true
route.UnescapePathValues = false
route.POST("/project/:name/build/:num", func(c *Context) {
name := c.Params.ByName("name")
num := c.Params.ByName("num")
assert.Equal(t, name, c.Param("name"))
assert.Equal(t, num, c.Param("num"))
assert.Equal(t, "Some%2FOther%2FProject", name)
assert.Equal(t, "333", num)
})
w := performRequest(route, "POST", "/project/Some%2FOther%2FProject/build/333")
assert.Equal(t, http.StatusOK, w.Code)
}
func TestRouteServeErrorWithWriteHeader(t *testing.T) {
route := New()
route.Use(func(c *Context) {
c.Status(421)
c.Next()
})
w := performRequest(route, "GET", "/NotFound")
assert.Equal(t, 421, w.Code)
assert.Equal(t, 0, w.Body.Len())
}