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"
|
|
|
|
"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, w.Code, http.StatusOK)
|
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, w.Code, http.StatusNotFound)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestSingleRouteOK tests that POST route is correctly invoked.
|
|
|
|
func testRouteNotOK2(method string, t *testing.T) {
|
|
|
|
passed := false
|
|
|
|
router := New()
|
|
|
|
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, w.Code, http.StatusMethodNotAllowed)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRouterGroupRouteOK(t *testing.T) {
|
2015-05-21 15:01:13 +00:00
|
|
|
testRouteOK("GET", t)
|
2015-04-08 00:58:35 +00:00
|
|
|
testRouteOK("POST", t)
|
|
|
|
testRouteOK("PUT", t)
|
2015-05-21 15:01:13 +00:00
|
|
|
testRouteOK("PATCH", t)
|
2015-04-08 00:58:35 +00:00
|
|
|
testRouteOK("HEAD", t)
|
2015-05-21 15:01:13 +00:00
|
|
|
testRouteOK("OPTIONS", t)
|
|
|
|
testRouteOK("DELETE", t)
|
|
|
|
testRouteOK("CONNECT", t)
|
|
|
|
testRouteOK("TRACE", t)
|
2015-04-08 00:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TestSingleRouteOK tests that POST route is correctly invoked.
|
|
|
|
func TestRouteNotOK(t *testing.T) {
|
2015-05-21 15:01:13 +00:00
|
|
|
testRouteNotOK("GET", t)
|
2015-04-08 00:58:35 +00:00
|
|
|
testRouteNotOK("POST", t)
|
|
|
|
testRouteNotOK("PUT", t)
|
2015-05-21 15:01:13 +00:00
|
|
|
testRouteNotOK("PATCH", t)
|
2015-04-08 00:58:35 +00:00
|
|
|
testRouteNotOK("HEAD", t)
|
2015-05-21 15:01:13 +00:00
|
|
|
testRouteNotOK("OPTIONS", t)
|
|
|
|
testRouteNotOK("DELETE", t)
|
|
|
|
testRouteNotOK("CONNECT", t)
|
|
|
|
testRouteNotOK("TRACE", t)
|
2015-04-08 00:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TestSingleRouteOK tests that POST route is correctly invoked.
|
|
|
|
func TestRouteNotOK2(t *testing.T) {
|
2015-05-21 15:01:13 +00:00
|
|
|
testRouteNotOK2("GET", t)
|
2015-04-08 00:58:35 +00:00
|
|
|
testRouteNotOK2("POST", t)
|
|
|
|
testRouteNotOK2("PUT", t)
|
2015-05-21 15:01:13 +00:00
|
|
|
testRouteNotOK2("PATCH", t)
|
2015-04-08 00:58:35 +00:00
|
|
|
testRouteNotOK2("HEAD", t)
|
2015-05-21 15:01:13 +00:00
|
|
|
testRouteNotOK2("OPTIONS", t)
|
|
|
|
testRouteNotOK2("DELETE", t)
|
|
|
|
testRouteNotOK2("CONNECT", t)
|
|
|
|
testRouteNotOK2("TRACE", t)
|
2015-04-08 00:58:35 +00:00
|
|
|
}
|
|
|
|
|
2015-05-05 13:06:38 +00:00
|
|
|
// 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 := ""
|
2015-05-05 13:06:38 +00:00
|
|
|
router := New()
|
2015-05-05 14:37:33 +00:00
|
|
|
router.GET("/test/:name/:last_name/*wild", func(c *Context) {
|
2015-05-05 13:06:38 +00:00
|
|
|
name = c.Params.ByName("name")
|
|
|
|
lastName = c.Params.ByName("last_name")
|
2015-05-05 14:37:33 +00:00
|
|
|
wild = c.Params.ByName("wild")
|
|
|
|
|
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-05 13:06:38 +00:00
|
|
|
})
|
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")
|
2015-05-05 13:06:38 +00:00
|
|
|
|
|
|
|
assert.Equal(t, w.Code, 200)
|
|
|
|
assert.Equal(t, name, "john")
|
|
|
|
assert.Equal(t, lastName, "smith")
|
2015-05-05 14:37:33 +00:00
|
|
|
assert.Equal(t, wild, "/is/super/great")
|
2015-05-05 13:06:38 +00:00
|
|
|
}
|
|
|
|
|
2015-04-08 00:58:35 +00:00
|
|
|
// TestHandleStaticFile - ensure the static file handles properly
|
2015-05-05 13:06:38 +00:00
|
|
|
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())
|
|
|
|
f.WriteString("Gin Web Framework")
|
|
|
|
f.Close()
|
|
|
|
|
2015-05-21 15:01:13 +00:00
|
|
|
dir, filename := path.Split(f.Name())
|
|
|
|
|
2015-04-08 00:58:35 +00:00
|
|
|
// SETUP gin
|
2015-05-18 18:50:46 +00:00
|
|
|
router := New()
|
2015-05-21 15:01:13 +00:00
|
|
|
router.Static("/using_static", dir)
|
|
|
|
router.StaticFile("/result", f.Name())
|
2015-04-08 00:58:35 +00:00
|
|
|
|
2015-05-21 15:01:13 +00:00
|
|
|
w := performRequest(router, "GET", "/using_static/"+filename)
|
|
|
|
w2 := performRequest(router, "GET", "/result")
|
2015-04-08 00:58:35 +00:00
|
|
|
|
2015-05-21 15:01:13 +00:00
|
|
|
assert.Equal(t, w, w2)
|
2015-04-08 12:24:49 +00:00
|
|
|
assert.Equal(t, w.Code, 200)
|
|
|
|
assert.Equal(t, w.Body.String(), "Gin Web Framework")
|
|
|
|
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
|
2015-05-21 15:01:13 +00:00
|
|
|
|
|
|
|
w3 := performRequest(router, "HEAD", "/using_static/"+filename)
|
|
|
|
w4 := performRequest(router, "HEAD", "/result")
|
|
|
|
|
|
|
|
assert.Equal(t, w3, w4)
|
|
|
|
assert.Equal(t, w3.Code, 200)
|
2015-04-08 00:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TestHandleStaticDir - ensure the root/sub dir handles properly
|
2015-05-21 15:01:13 +00:00
|
|
|
func TestRouteStaticListingDir(t *testing.T) {
|
2015-05-18 18:50:46 +00:00
|
|
|
router := New()
|
2015-05-24 14:29:55 +00:00
|
|
|
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
|
|
|
|
2015-04-08 12:24:49 +00:00
|
|
|
assert.Equal(t, w.Code, 200)
|
2015-05-18 18:50:46 +00:00
|
|
|
assert.Contains(t, w.Body.String(), "gin.go")
|
2015-04-08 12:24:49 +00:00
|
|
|
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/html; charset=utf-8")
|
2015-04-08 00:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TestHandleHeadToDir - ensure the root/sub dir handles properly
|
2015-05-21 15:01:13 +00:00
|
|
|
func TestRouteStaticNoListing(t *testing.T) {
|
2015-04-08 00:58:35 +00:00
|
|
|
router := New()
|
|
|
|
router.Static("/", "./")
|
|
|
|
|
2015-05-21 15:01:13 +00:00
|
|
|
w := performRequest(router, "GET", "/")
|
2015-04-08 00:58:35 +00:00
|
|
|
|
2015-05-24 15:03:44 +00:00
|
|
|
assert.Equal(t, w.Code, 404)
|
2015-05-21 15:01:13 +00:00
|
|
|
assert.NotContains(t, w.Body.String(), "gin.go")
|
2015-05-18 18:50:46 +00:00
|
|
|
}
|
2015-05-18 18:51:08 +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("/", "./")
|
|
|
|
|
2015-05-21 15:01:13 +00:00
|
|
|
w := performRequest(router, "GET", "/gin.go")
|
2015-05-18 18:51:08 +00:00
|
|
|
|
|
|
|
assert.Equal(t, w.Code, 200)
|
2015-05-21 15:01:13 +00:00
|
|
|
assert.Contains(t, w.Body.String(), "package gin")
|
|
|
|
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
|
2015-05-18 18:51:08 +00:00
|
|
|
assert.NotEqual(t, w.HeaderMap.Get("Last-Modified"), "Mon, 02 Jan 2006 15:04:05 MST")
|
|
|
|
assert.Equal(t, w.HeaderMap.Get("Expires"), "Mon, 02 Jan 2006 15:04:05 MST")
|
|
|
|
assert.Equal(t, w.HeaderMap.Get("x-GIN"), "Gin Framework")
|
2015-04-08 00:58:35 +00:00
|
|
|
}
|
2015-05-05 14:37:33 +00:00
|
|
|
|
|
|
|
func TestRouteNotAllowed(t *testing.T) {
|
|
|
|
router := New()
|
|
|
|
|
|
|
|
router.POST("/path", func(c *Context) {})
|
|
|
|
w := performRequest(router, "GET", "/path")
|
|
|
|
assert.Equal(t, w.Code, http.StatusMethodNotAllowed)
|
|
|
|
|
|
|
|
router.NoMethod(func(c *Context) {
|
|
|
|
c.String(http.StatusTeapot, "responseText")
|
|
|
|
})
|
|
|
|
w = performRequest(router, "GET", "/path")
|
|
|
|
assert.Equal(t, w.Body.String(), "responseText")
|
|
|
|
assert.Equal(t, w.Code, http.StatusTeapot)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRouterNotFound(t *testing.T) {
|
|
|
|
router := New()
|
|
|
|
router.GET("/path", func(c *Context) {})
|
|
|
|
router.GET("/dir/", func(c *Context) {})
|
|
|
|
router.GET("/", func(c *Context) {})
|
|
|
|
|
|
|
|
testRoutes := []struct {
|
|
|
|
route string
|
|
|
|
code int
|
|
|
|
header string
|
|
|
|
}{
|
|
|
|
{"/path/", 301, "map[Location:[/path]]"}, // TSR -/
|
|
|
|
{"/dir", 301, "map[Location:[/dir/]]"}, // TSR +/
|
|
|
|
{"", 301, "map[Location:[/]]"}, // TSR +/
|
|
|
|
{"/PATH", 301, "map[Location:[/path]]"}, // Fixed Case
|
|
|
|
{"/DIR/", 301, "map[Location:[/dir/]]"}, // Fixed Case
|
|
|
|
{"/PATH/", 301, "map[Location:[/path]]"}, // Fixed Case -/
|
|
|
|
{"/DIR", 301, "map[Location:[/dir/]]"}, // Fixed Case +/
|
|
|
|
{"/../path", 301, "map[Location:[/path]]"}, // CleanPath
|
|
|
|
{"/nope", 404, ""}, // NotFound
|
|
|
|
}
|
|
|
|
for _, tr := range testRoutes {
|
|
|
|
w := performRequest(router, "GET", tr.route)
|
|
|
|
assert.Equal(t, w.Code, tr.code)
|
|
|
|
if w.Code != 404 {
|
|
|
|
assert.Equal(t, fmt.Sprint(w.Header()), tr.header)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test custom not found handler
|
|
|
|
var notFound bool
|
|
|
|
router.NoRoute(func(c *Context) {
|
|
|
|
c.AbortWithStatus(404)
|
|
|
|
notFound = true
|
|
|
|
})
|
|
|
|
w := performRequest(router, "GET", "/nope")
|
|
|
|
assert.Equal(t, w.Code, 404)
|
|
|
|
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, w.Code, 307)
|
|
|
|
assert.Equal(t, fmt.Sprint(w.Header()), "map[Location:[/path]]")
|
|
|
|
|
|
|
|
// 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, w.Code, 404)
|
|
|
|
}
|