mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
Fasthttp seems have little bug with headers, so make a VisitAllCookies function and GetFlashes completed- tests added also
This commit is contained in:
parent
2cc75817b7
commit
01914b6c37
|
@ -34,7 +34,7 @@ type (
|
|||
Redis struct {
|
||||
// Network "tcp"
|
||||
Network string
|
||||
// Addr "127.0.01:6379"
|
||||
// Addr "127.0.0.1:6379"
|
||||
Addr string
|
||||
// Password string .If no password then no 'AUTH'. Default ""
|
||||
Password string
|
||||
|
|
|
@ -2,12 +2,13 @@ package config
|
|||
|
||||
// Tester configuration
|
||||
type Tester struct {
|
||||
Debug bool
|
||||
ListeningAddr string
|
||||
ExplicitURL bool
|
||||
Debug bool
|
||||
}
|
||||
|
||||
// DefaultTester returns the default configuration for a tester
|
||||
// the ListeningAddr is used as virtual only when no running server is founded
|
||||
func DefaultTester() Tester {
|
||||
return Tester{Debug: false, ListeningAddr: "iris-go.com:1993"}
|
||||
return Tester{ListeningAddr: "iris-go.com:1993", ExplicitURL: false, Debug: false}
|
||||
}
|
||||
|
|
126
context.go
126
context.go
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
Context.go Implements: ./context/context.go ,
|
||||
files: context_renderer.go, context_storage.go, context_request.go, context_response.go
|
||||
Context.go Implements: ./context/context.go
|
||||
*/
|
||||
|
||||
package iris
|
||||
|
@ -56,6 +55,9 @@ const (
|
|||
stopExecutionPosition = 255
|
||||
// used inside GetFlash to store the lifetime request flash messages
|
||||
flashMessagesStoreContextKey = "_iris_flash_messages_"
|
||||
flashMessageCookiePrefix = "_iris_flash_message_"
|
||||
cookieHeaderID = "Cookie: "
|
||||
cookieHeaderIDLen = len(cookieHeaderID)
|
||||
)
|
||||
|
||||
// this pool is used everywhere needed in the iris for example inside party-> Static
|
||||
|
@ -286,6 +288,11 @@ func (ctx *Context) RequestHeader(k string) string {
|
|||
|
||||
// PostFormValue returns a single value from post request's data
|
||||
func (ctx *Context) PostFormValue(name string) string {
|
||||
return ctx.FormValueString(name)
|
||||
}
|
||||
|
||||
// FormValueString returns a single value, as string, from post request's data
|
||||
func (ctx *Context) FormValueString(name string) string {
|
||||
return string(ctx.FormValue(name))
|
||||
}
|
||||
|
||||
|
@ -314,7 +321,7 @@ func (ctx *Context) Subdomain() (subdomain string) {
|
|||
// use it only for special cases, when the default behavior doesn't suits you.
|
||||
//
|
||||
// http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
|
||||
/* Credits to Manish Singh @kryptodev for URLEncode */
|
||||
/* Credits to Manish Singh @kryptodev for URLEncode by post issue share code */
|
||||
func URLEncode(path string) string {
|
||||
if path == "" {
|
||||
return ""
|
||||
|
@ -691,6 +698,28 @@ func (ctx *Context) Set(key string, value interface{}) {
|
|||
ctx.RequestCtx.SetUserValue(key, value)
|
||||
}
|
||||
|
||||
// VisitAllCookies takes a visitor which loops on each (request's) cookie key and value
|
||||
//
|
||||
// Note: the method ctx.Request.Header.VisitAllCookie by fasthttp, has a strange bug which I cannot solve at the moment.
|
||||
// This is the reason which this function exists and should be used instead of fasthttp's built'n.
|
||||
func (ctx *Context) VisitAllCookies(visitor func(key string, value string)) {
|
||||
// strange bug, this doesnt works also: cookieHeaderContent := ctx.Request.Header.Peek("Cookie")/User-Agent tested also
|
||||
headerbody := string(ctx.Request.Header.Header())
|
||||
headerlines := strings.Split(headerbody, "\n")
|
||||
for _, s := range headerlines {
|
||||
if len(s) > cookieHeaderIDLen {
|
||||
if s[0:cookieHeaderIDLen] == cookieHeaderID {
|
||||
contents := s[cookieHeaderIDLen:]
|
||||
values := strings.Split(contents, "; ")
|
||||
for _, s := range values {
|
||||
keyvalue := strings.SplitN(s, "=", 2)
|
||||
visitor(keyvalue[0], keyvalue[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetCookie returns cookie's value by it's name
|
||||
// returns empty string if nothing was found
|
||||
func (ctx *Context) GetCookie(name string) (val string) {
|
||||
|
@ -723,19 +752,64 @@ func (ctx *Context) RemoveCookie(name string) {
|
|||
ctx.RequestCtx.Response.Header.DelClientCookie(name)
|
||||
}
|
||||
|
||||
// GetFlashes returns all the flash messages for available for this request
|
||||
func (ctx *Context) GetFlashes() map[string]string {
|
||||
// if already taken at least one time, this will be filled
|
||||
if messages := ctx.Get(flashMessagesStoreContextKey); messages != nil {
|
||||
if m, isMap := messages.(map[string]string); isMap {
|
||||
return m
|
||||
}
|
||||
} else {
|
||||
flashMessageFound := false
|
||||
// else first time, get all flash cookie keys(the prefix will tell us which is a flash message), and after get all one-by-one using the GetFlash.
|
||||
flashMessageCookiePrefixLen := len(flashMessageCookiePrefix)
|
||||
ctx.VisitAllCookies(func(key string, value string) {
|
||||
if len(key) > flashMessageCookiePrefixLen {
|
||||
if key[0:flashMessageCookiePrefixLen] == flashMessageCookiePrefix {
|
||||
unprefixedKey := key[flashMessageCookiePrefixLen:]
|
||||
_, err := ctx.GetFlash(unprefixedKey) // this func will add to the list (flashMessagesStoreContextKey) also
|
||||
if err == nil {
|
||||
flashMessageFound = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
// if we found at least one flash message then re-execute this function to return the list
|
||||
if flashMessageFound {
|
||||
return ctx.GetFlashes()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctx *Context) decodeFlashCookie(key string) (string, string) {
|
||||
cookieKey := flashMessageCookiePrefix + key
|
||||
cookieValue := string(ctx.RequestCtx.Request.Header.Cookie(cookieKey))
|
||||
|
||||
if cookieValue != "" {
|
||||
v, e := base64.URLEncoding.DecodeString(cookieValue)
|
||||
if e == nil {
|
||||
return cookieKey, string(v)
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
// GetFlash get a flash message by it's key
|
||||
// returns the value as string and an error
|
||||
//
|
||||
// if the cookie doesn't exists the string is empty and the error is filled
|
||||
// after the request's life the value is removed
|
||||
func (ctx *Context) GetFlash(key string) (value string, err error) {
|
||||
func (ctx *Context) GetFlash(key string) (string, error) {
|
||||
|
||||
// first check if flash exists from this request's lifetime, if yes return that else continue to get the cookie
|
||||
storeExists := false
|
||||
|
||||
if messages := ctx.Get(flashMessagesStoreContextKey); messages != nil {
|
||||
m, isMap := messages.(map[string]string)
|
||||
if !isMap {
|
||||
return "", fmt.Errorf("Messages request's store is not a map[string]string. This suppose will never happen, please report this bug.")
|
||||
return "", fmt.Errorf("Flash store is not a map[string]string. This suppose will never happen, please report this bug.")
|
||||
}
|
||||
storeExists = true // in order to skip the check later
|
||||
for k, v := range m {
|
||||
|
@ -745,38 +819,32 @@ func (ctx *Context) GetFlash(key string) (value string, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
cookieValue := string(ctx.RequestCtx.Request.Header.Cookie(key))
|
||||
|
||||
cookieKey, cookieValue := ctx.decodeFlashCookie(key)
|
||||
if cookieValue == "" {
|
||||
err = errFlashNotFound.Return()
|
||||
} else {
|
||||
v, e := base64.URLEncoding.DecodeString(cookieValue)
|
||||
if e != nil {
|
||||
return "", err
|
||||
}
|
||||
value = string(v)
|
||||
// store this flash message to the lifetime request's local storage,
|
||||
// I choose this method because no need to store it if not used at all
|
||||
if storeExists {
|
||||
ctx.Get(flashMessagesStoreContextKey).(map[string]string)[key] = value
|
||||
} else {
|
||||
flashStoreMap := make(map[string]string)
|
||||
flashStoreMap[key] = value
|
||||
ctx.Set(flashMessagesStoreContextKey, flashStoreMap)
|
||||
}
|
||||
|
||||
//remove the real cookie, no need to have that, we stored it on lifetime request
|
||||
ctx.RemoveCookie(key)
|
||||
//it should'b be removed until the next reload, so we don't do that: ctx.Request.Header.SetCookie(key, "")
|
||||
return "", errFlashNotFound.Return()
|
||||
}
|
||||
return
|
||||
// store this flash message to the lifetime request's local storage,
|
||||
// I choose this method because no need to store it if not used at all
|
||||
if storeExists {
|
||||
ctx.Get(flashMessagesStoreContextKey).(map[string]string)[key] = cookieValue
|
||||
} else {
|
||||
flashStoreMap := make(map[string]string)
|
||||
flashStoreMap[key] = cookieValue
|
||||
ctx.Set(flashMessagesStoreContextKey, flashStoreMap)
|
||||
}
|
||||
|
||||
//remove the real cookie, no need to have that, we stored it on lifetime request
|
||||
ctx.RemoveCookie(cookieKey)
|
||||
return cookieValue, nil
|
||||
//it should'b be removed until the next reload, so we don't do that: ctx.Request.Header.SetCookie(key, "")
|
||||
|
||||
}
|
||||
|
||||
// SetFlash sets a flash message, accepts 2 parameters the key(string) and the value(string)
|
||||
// the value will be available on the NEXT request
|
||||
func (ctx *Context) SetFlash(key string, value string) {
|
||||
c := fasthttp.AcquireCookie()
|
||||
c.SetKey(key)
|
||||
c.SetKey(flashMessageCookiePrefix + key)
|
||||
c.SetValue(base64.URLEncoding.EncodeToString([]byte(value)))
|
||||
c.SetPath("/")
|
||||
c.SetHTTPOnly(true)
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
package iris
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Contains tests for context.ReadJSON/ReadXML/ReadFORM
|
||||
|
||||
type testBinderData struct {
|
||||
Username string
|
||||
Mail string
|
||||
Data []string `form:"mydata" json:"mydata"`
|
||||
}
|
||||
|
||||
type testBinderXMLData struct {
|
||||
XMLName xml.Name `xml:"info"`
|
||||
FirstAttr string `xml:"first,attr"`
|
||||
SecondAttr string `xml:"second,attr"`
|
||||
Name string `xml:"name",json:"name"`
|
||||
Birth string `xml:"birth",json:"birth"`
|
||||
Stars int `xml:"stars",json:"stars"`
|
||||
}
|
||||
|
||||
func TestBindForm(t *testing.T) {
|
||||
initDefault()
|
||||
|
||||
Post("/form", func(ctx *Context) {
|
||||
obj := testBinderData{}
|
||||
err := ctx.ReadForm(&obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Error when parsing the FORM: %s", err.Error())
|
||||
}
|
||||
ctx.JSON(StatusOK, obj)
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
|
||||
passed := map[string]interface{}{"Username": "myusername", "Mail": "mymail@iris-go.com", "mydata": url.Values{"[0]": []string{"mydata1"},
|
||||
"[1]": []string{"mydata2"}}}
|
||||
|
||||
expectedObject := testBinderData{Username: "myusername", Mail: "mymail@iris-go.com", Data: []string{"mydata1", "mydata2"}}
|
||||
|
||||
e.POST("/form").WithForm(passed).Expect().Status(StatusOK).JSON().Object().Equal(expectedObject)
|
||||
}
|
||||
|
||||
func TestBindJSON(t *testing.T) {
|
||||
initDefault()
|
||||
Post("/json", func(ctx *Context) {
|
||||
obj := testBinderData{}
|
||||
err := ctx.ReadJSON(&obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Error when parsing the JSON body: %s", err.Error())
|
||||
}
|
||||
ctx.JSON(StatusOK, obj)
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
passed := map[string]interface{}{"Username": "myusername", "Mail": "mymail@iris-go.com", "mydata": []string{"mydata1", "mydata2"}}
|
||||
expectedObject := testBinderData{Username: "myusername", Mail: "mymail@iris-go.com", Data: []string{"mydata1", "mydata2"}}
|
||||
|
||||
e.POST("/json").WithJSON(passed).Expect().Status(StatusOK).JSON().Object().Equal(expectedObject)
|
||||
}
|
||||
|
||||
func TestBindXML(t *testing.T) {
|
||||
initDefault()
|
||||
|
||||
Post("/xml", func(ctx *Context) {
|
||||
obj := testBinderXMLData{}
|
||||
err := ctx.ReadXML(&obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Error when parsing the XML body: %s", err.Error())
|
||||
}
|
||||
ctx.XML(StatusOK, obj)
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
expectedObj := testBinderXMLData{
|
||||
XMLName: xml.Name{Local: "info", Space: "info"},
|
||||
FirstAttr: "this is the first attr",
|
||||
SecondAttr: "this is the second attr",
|
||||
Name: "Iris web framework",
|
||||
Birth: "13 March 2016",
|
||||
Stars: 4064,
|
||||
}
|
||||
// so far no WithXML or .XML like WithJSON and .JSON on httpexpect I added a feature request as post issue and we're waiting
|
||||
expectedBody := `<` + expectedObj.XMLName.Local + ` first="` + expectedObj.FirstAttr + `" second="` + expectedObj.SecondAttr + `"><name>` + expectedObj.Name + `</name><birth>` + expectedObj.Birth + `</birth><stars>` + strconv.Itoa(expectedObj.Stars) + `</stars></info>`
|
||||
e.POST("/xml").WithText(expectedBody).Expect().Status(StatusOK).Body().Equal(expectedBody)
|
||||
}
|
401
context_test.go
401
context_test.go
|
@ -1,6 +1,11 @@
|
|||
package iris
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"encoding/xml"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestContextReset(t *testing.T) {
|
||||
var context Context
|
||||
|
@ -72,7 +77,7 @@ func TestContextDoNextStop(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestContextParam(t *testing.T) {
|
||||
func TestContextParams(t *testing.T) {
|
||||
var context Context
|
||||
params := PathParameters{
|
||||
PathParameter{Key: "testkey", Value: "testvalue"},
|
||||
|
@ -104,8 +109,396 @@ func TestContextParam(t *testing.T) {
|
|||
} else if vi != 548921854390354 {
|
||||
t.Fatalf("Expecting to receive %d but we got %d", 548921854390354, vi)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContextURLParam(t *testing.T) {
|
||||
// end-to-end test now, note that we will not test the whole mux here, this happens on http_test.go
|
||||
|
||||
initDefault()
|
||||
expectedParamsStr := "param1=myparam1,param2=myparam2,param3=myparam3afterstatic,anything=/andhere/anything/you/like"
|
||||
Get("/path/:param1/:param2/staticpath/:param3/*anything", func(ctx *Context) {
|
||||
paramsStr := ctx.Params.String()
|
||||
ctx.Write(paramsStr)
|
||||
})
|
||||
|
||||
Tester(t).GET("/path/myparam1/myparam2/staticpath/myparam3afterstatic/andhere/anything/you/like").Expect().Status(StatusOK).Body().Equal(expectedParamsStr)
|
||||
|
||||
}
|
||||
|
||||
func TestContextURLParams(t *testing.T) {
|
||||
initDefault()
|
||||
passedParams := map[string]string{"param1": "value1", "param2": "value2"}
|
||||
Get("/", func(ctx *Context) {
|
||||
params := ctx.URLParams()
|
||||
ctx.JSON(StatusOK, params)
|
||||
})
|
||||
e := Tester(t)
|
||||
|
||||
e.GET("/").WithQueryObject(passedParams).Expect().Status(StatusOK).JSON().Equal(passedParams)
|
||||
}
|
||||
|
||||
// hoststring returns the full host, will return the HOST:IP
|
||||
func TestContextHostString(t *testing.T) {
|
||||
initDefault()
|
||||
Config.Tester.ListeningAddr = "localhost:8080"
|
||||
Get("/", func(ctx *Context) {
|
||||
ctx.Write(ctx.HostString())
|
||||
})
|
||||
|
||||
Get("/wrong", func(ctx *Context) {
|
||||
ctx.Write(ctx.HostString() + "w")
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
e.GET("/").Expect().Status(StatusOK).Body().Equal(Config.Tester.ListeningAddr)
|
||||
e.GET("/wrong").Expect().Body().NotEqual(Config.Tester.ListeningAddr)
|
||||
}
|
||||
|
||||
// VirtualHostname returns the hostname only,
|
||||
// if the host starts with 127.0.0.1 or localhost it gives the registered hostname part of the listening addr
|
||||
func TestContextVirtualHostName(t *testing.T) {
|
||||
initDefault()
|
||||
vhost := "mycustomvirtualname.com"
|
||||
Config.Tester.ListeningAddr = vhost + ":8080"
|
||||
Get("/", func(ctx *Context) {
|
||||
ctx.Write(ctx.VirtualHostname())
|
||||
})
|
||||
|
||||
Get("/wrong", func(ctx *Context) {
|
||||
ctx.Write(ctx.VirtualHostname() + "w")
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
e.GET("/").Expect().Status(StatusOK).Body().Equal(vhost)
|
||||
e.GET("/wrong").Expect().Body().NotEqual(vhost)
|
||||
}
|
||||
|
||||
func TestContextFormValueString(t *testing.T) {
|
||||
initDefault()
|
||||
var k, v string
|
||||
k = "postkey"
|
||||
v = "postvalue"
|
||||
Post("/", func(ctx *Context) {
|
||||
ctx.Write(k + "=" + ctx.FormValueString(k))
|
||||
})
|
||||
e := Tester(t)
|
||||
|
||||
e.POST("/").WithFormField(k, v).Expect().Status(StatusOK).Body().Equal(k + "=" + v)
|
||||
}
|
||||
|
||||
func TestContextSubdomain(t *testing.T) {
|
||||
initDefault()
|
||||
Config.Tester.ListeningAddr = "mydomain.com:9999"
|
||||
//Config.Tester.ExplicitURL = true
|
||||
Party("mysubdomain.").Get("/mypath", func(ctx *Context) {
|
||||
ctx.Write(ctx.Subdomain())
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
e.GET("/").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusNotFound)
|
||||
e.GET("/mypath").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusOK).Body().Equal("mysubdomain")
|
||||
|
||||
//e.GET("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusNotFound)
|
||||
//e.GET("http://mysubdomain.mydomain.com:9999/mypath").Expect().Status(StatusOK).Body().Equal("mysubdomain")
|
||||
}
|
||||
|
||||
type testBinderData struct {
|
||||
Username string
|
||||
Mail string
|
||||
Data []string `form:"mydata" json:"mydata"`
|
||||
}
|
||||
|
||||
type testBinderXMLData struct {
|
||||
XMLName xml.Name `xml:"info"`
|
||||
FirstAttr string `xml:"first,attr"`
|
||||
SecondAttr string `xml:"second,attr"`
|
||||
Name string `xml:"name",json:"name"`
|
||||
Birth string `xml:"birth",json:"birth"`
|
||||
Stars int `xml:"stars",json:"stars"`
|
||||
}
|
||||
|
||||
func TestContextReadForm(t *testing.T) {
|
||||
initDefault()
|
||||
|
||||
Post("/form", func(ctx *Context) {
|
||||
obj := testBinderData{}
|
||||
err := ctx.ReadForm(&obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Error when parsing the FORM: %s", err.Error())
|
||||
}
|
||||
ctx.JSON(StatusOK, obj)
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
|
||||
passed := map[string]interface{}{"Username": "myusername", "Mail": "mymail@iris-go.com", "mydata": url.Values{"[0]": []string{"mydata1"},
|
||||
"[1]": []string{"mydata2"}}}
|
||||
|
||||
expectedObject := testBinderData{Username: "myusername", Mail: "mymail@iris-go.com", Data: []string{"mydata1", "mydata2"}}
|
||||
|
||||
e.POST("/form").WithForm(passed).Expect().Status(StatusOK).JSON().Object().Equal(expectedObject)
|
||||
}
|
||||
|
||||
func TestContextReadJSON(t *testing.T) {
|
||||
initDefault()
|
||||
Post("/json", func(ctx *Context) {
|
||||
obj := testBinderData{}
|
||||
err := ctx.ReadJSON(&obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Error when parsing the JSON body: %s", err.Error())
|
||||
}
|
||||
ctx.JSON(StatusOK, obj)
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
passed := map[string]interface{}{"Username": "myusername", "Mail": "mymail@iris-go.com", "mydata": []string{"mydata1", "mydata2"}}
|
||||
expectedObject := testBinderData{Username: "myusername", Mail: "mymail@iris-go.com", Data: []string{"mydata1", "mydata2"}}
|
||||
|
||||
e.POST("/json").WithJSON(passed).Expect().Status(StatusOK).JSON().Object().Equal(expectedObject)
|
||||
}
|
||||
|
||||
func TestContextReadXML(t *testing.T) {
|
||||
initDefault()
|
||||
|
||||
Post("/xml", func(ctx *Context) {
|
||||
obj := testBinderXMLData{}
|
||||
err := ctx.ReadXML(&obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Error when parsing the XML body: %s", err.Error())
|
||||
}
|
||||
ctx.XML(StatusOK, obj)
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
expectedObj := testBinderXMLData{
|
||||
XMLName: xml.Name{Local: "info", Space: "info"},
|
||||
FirstAttr: "this is the first attr",
|
||||
SecondAttr: "this is the second attr",
|
||||
Name: "Iris web framework",
|
||||
Birth: "13 March 2016",
|
||||
Stars: 4064,
|
||||
}
|
||||
// so far no WithXML or .XML like WithJSON and .JSON on httpexpect I added a feature request as post issue and we're waiting
|
||||
expectedBody := `<` + expectedObj.XMLName.Local + ` first="` + expectedObj.FirstAttr + `" second="` + expectedObj.SecondAttr + `"><name>` + expectedObj.Name + `</name><birth>` + expectedObj.Birth + `</birth><stars>` + strconv.Itoa(expectedObj.Stars) + `</stars></info>`
|
||||
e.POST("/xml").WithText(expectedBody).Expect().Status(StatusOK).Body().Equal(expectedBody)
|
||||
}
|
||||
|
||||
func TestContextRedirect(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestContextUserValues(t *testing.T) {
|
||||
initDefault()
|
||||
testCustomObjUserValue := struct{ Name string }{Name: "a name"}
|
||||
values := map[string]interface{}{"key1": "value1", "key2": "value2", "key3": 3, "key4": testCustomObjUserValue, "key5": map[string]string{"key": "value"}}
|
||||
|
||||
Get("/test", func(ctx *Context) {
|
||||
|
||||
for k, v := range values {
|
||||
ctx.Set(k, v)
|
||||
}
|
||||
|
||||
}, func(ctx *Context) {
|
||||
for k, v := range values {
|
||||
userValue := ctx.Get(k)
|
||||
if userValue != v {
|
||||
t.Fatalf("Expecting user value: %s to be equal with: %#v but got: %#v", k, v, userValue)
|
||||
}
|
||||
|
||||
if m, isMap := userValue.(map[string]string); isMap {
|
||||
if m["key"] != v.(map[string]string)["key"] {
|
||||
t.Fatalf("Expecting user value: %s to be equal with: %#v but got: %#v", k, v.(map[string]string)["key"], m["key"])
|
||||
}
|
||||
} else {
|
||||
if userValue != v {
|
||||
t.Fatalf("Expecting user value: %s to be equal with: %#v but got: %#v", k, v, userValue)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
|
||||
e.GET("/test").Expect().Status(StatusOK)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
NOTES OTAN ERTHW:
|
||||
|
||||
EDW EXW TO PROVLIMA GIATI ENOEITE OTI TO CONTEXT DN DIATERIRE SE OLA ARA DN BORW NA ELENKSW STO GETFLASHES kAI STO GETFLASH TAUTOXRONA TO IDIO CONTEXT KEY SE DIAFORETIKA REQUESTS, NA DW TO APO PANW TEST, NA TO KOITAKSW
|
||||
TA MAPS DOULEVOUN KALA KATI ALLO EINAI TO PROVLIMA
|
||||
*/
|
||||
func TestContextFlashMessages(t *testing.T) {
|
||||
initDefault()
|
||||
firstKey := "name"
|
||||
lastKey := "package"
|
||||
|
||||
values := map[string]string{firstKey: "kataras", lastKey: "iris"}
|
||||
|
||||
// set the flashes, the cookies are filled
|
||||
Put("/set", func(ctx *Context) {
|
||||
for k, v := range values {
|
||||
ctx.SetFlash(k, v)
|
||||
}
|
||||
})
|
||||
|
||||
// get the first flash, the next should be avaiable to the next requess
|
||||
Get("/get_first_flash", func(ctx *Context) {
|
||||
for k := range values {
|
||||
v, _ := ctx.GetFlash(k)
|
||||
ctx.JSON(StatusOK, map[string]string{k: v})
|
||||
break
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
// just an empty handler to test if the flashes should remeain to the next if GetFlash/GetFlashes used
|
||||
Get("/get_no_getflash", func(ctx *Context) {
|
||||
})
|
||||
|
||||
// get the last flash, the next should be avaiable to the next requess
|
||||
Get("/get_last_flash", func(ctx *Context) {
|
||||
i := 0
|
||||
for k := range values {
|
||||
i++
|
||||
if i == len(values) {
|
||||
v, _ := ctx.GetFlash(k)
|
||||
ctx.JSON(StatusOK, map[string]string{k: v})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Get("/get_zero_flashes", func(ctx *Context) {
|
||||
ctx.JSON(StatusOK, ctx.GetFlashes()) // should return nil
|
||||
})
|
||||
|
||||
// we use the GetFlash to get the flash messages, the messages and the cookies should be empty after that
|
||||
Get("/get_flash", func(ctx *Context) {
|
||||
kv := make(map[string]string)
|
||||
for k := range values {
|
||||
v, err := ctx.GetFlash(k)
|
||||
if err == nil {
|
||||
kv[k] = v
|
||||
}
|
||||
}
|
||||
ctx.JSON(StatusOK, kv)
|
||||
}, func(ctx *Context) {
|
||||
// at the same request, flashes should be available
|
||||
if len(ctx.GetFlashes()) == 0 {
|
||||
t.Fatalf("Flashes should be remeain to the whole request lifetime")
|
||||
}
|
||||
})
|
||||
|
||||
Get("/get_flashes", func(ctx *Context) {
|
||||
// one time one handler, using GetFlashes
|
||||
kv := make(map[string]string)
|
||||
flashes := ctx.GetFlashes()
|
||||
//second time on the same handler, using the GetFlash
|
||||
for k := range flashes {
|
||||
kv[k], _ = ctx.GetFlash(k)
|
||||
}
|
||||
if len(flashes) != len(kv) {
|
||||
ctx.SetStatusCode(StatusNoContent)
|
||||
return
|
||||
}
|
||||
ctx.Next()
|
||||
|
||||
}, func(ctx *Context) {
|
||||
// third time on a next handler
|
||||
// test the if next handler has access to them(must) because flash are request lifetime now.
|
||||
// print them to the client for test the response also
|
||||
ctx.JSON(StatusOK, ctx.GetFlashes())
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
e.PUT("/set").Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
e.GET("/get_first_flash").Expect().Status(StatusOK).JSON().Object().ContainsKey(firstKey).NotContainsKey(lastKey)
|
||||
// just a request which does not use the flash message, so flash messages should be available on the next request
|
||||
e.GET("/get_no_getflash").Expect().Status(StatusOK)
|
||||
e.GET("/get_last_flash").Expect().Status(StatusOK).JSON().Object().ContainsKey(lastKey).NotContainsKey(firstKey)
|
||||
g := e.GET("/get_zero_flashes").Expect().Status(StatusOK)
|
||||
g.JSON().Null()
|
||||
g.Cookies().Empty()
|
||||
// set the magain
|
||||
e.PUT("/set").Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
// get them again using GetFlash
|
||||
e.GET("/get_flash").Expect().Status(StatusOK).JSON().Object().Equal(values)
|
||||
// this should be empty again
|
||||
g = e.GET("/get_zero_flashes").Expect().Status(StatusOK)
|
||||
g.JSON().Null()
|
||||
g.Cookies().Empty()
|
||||
//set them again
|
||||
e.PUT("/set").Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
// get them again using GetFlashes
|
||||
e.GET("/get_flashes").Expect().Status(StatusOK).JSON().Object().Equal(values)
|
||||
// this should be empty again
|
||||
g = e.GET("/get_zero_flashes").Expect().Status(StatusOK)
|
||||
g.JSON().Null()
|
||||
g.Cookies().Empty()
|
||||
|
||||
}
|
||||
|
||||
func TestContextSessions(t *testing.T) {
|
||||
t.Parallel()
|
||||
values := map[string]interface{}{
|
||||
"Name": "iris",
|
||||
"Months": "4",
|
||||
"Secret": "dsads£2132215£%%Ssdsa",
|
||||
}
|
||||
|
||||
initDefault()
|
||||
Config.Sessions.Cookie = "mycustomsessionid"
|
||||
|
||||
writeValues := func(ctx *Context) {
|
||||
sessValues := ctx.Session().GetAll()
|
||||
ctx.JSON(StatusOK, sessValues)
|
||||
}
|
||||
|
||||
if testEnableSubdomain {
|
||||
Party(testSubdomain+".").Get("/get", func(ctx *Context) {
|
||||
writeValues(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
Post("set", func(ctx *Context) {
|
||||
vals := make(map[string]interface{}, 0)
|
||||
if err := ctx.ReadJSON(&vals); err != nil {
|
||||
t.Fatalf("Cannot readjson. Trace %s", err.Error())
|
||||
}
|
||||
for k, v := range vals {
|
||||
ctx.Session().Set(k, v)
|
||||
}
|
||||
})
|
||||
|
||||
Get("/get", func(ctx *Context) {
|
||||
writeValues(ctx)
|
||||
})
|
||||
|
||||
Get("/clear", func(ctx *Context) {
|
||||
ctx.Session().Clear()
|
||||
writeValues(ctx)
|
||||
})
|
||||
|
||||
Get("/destroy", func(ctx *Context) {
|
||||
ctx.SessionDestroy()
|
||||
writeValues(ctx)
|
||||
// the cookie and all values should be empty
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
|
||||
e.POST("/set").WithJSON(values).Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
e.GET("/get").Expect().Status(StatusOK).JSON().Object().Equal(values)
|
||||
if testEnableSubdomain {
|
||||
es := subdomainTester(e)
|
||||
es.Request("GET", "/get").Expect().Status(StatusOK).JSON().Object().Equal(values)
|
||||
}
|
||||
|
||||
// test destory which also clears first
|
||||
d := e.GET("/destroy").Expect().Status(StatusOK)
|
||||
d.JSON().Object().Empty()
|
||||
d.Cookies().ContainsOnly(Config.Sessions.Cookie)
|
||||
// set and clear again
|
||||
e.POST("/set").WithJSON(values).Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
e.GET("/clear").Expect().Status(StatusOK).JSON().Object().Empty()
|
||||
}
|
||||
|
|
5
iris.go
5
iris.go
|
@ -284,7 +284,6 @@ func (s *Framework) Go() error {
|
|||
s.Plugins.DoPreListen(s)
|
||||
|
||||
if firstErr := s.Servers.OpenAll(); firstErr != nil {
|
||||
panic("iris:287")
|
||||
return firstErr
|
||||
}
|
||||
|
||||
|
@ -822,6 +821,10 @@ func NewTester(api *Framework, t *testing.T) *httpexpect.Expect {
|
|||
}
|
||||
}
|
||||
|
||||
if api.Config.Tester.ExplicitURL {
|
||||
baseURL = ""
|
||||
}
|
||||
|
||||
testConfiguration := httpexpect.Config{
|
||||
BaseURL: baseURL,
|
||||
Client: &http.Client{
|
||||
|
|
|
@ -19,15 +19,11 @@ var _ store.IStore = &Store{}
|
|||
|
||||
// GetAll returns all values
|
||||
func (s *Store) GetAll() map[string]interface{} {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.values
|
||||
}
|
||||
|
||||
// VisitAll loop each one entry and calls the callback function func(key,value)
|
||||
func (s *Store) VisitAll(cb func(k string, v interface{})) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for key := range s.values {
|
||||
cb(key, s.values[key])
|
||||
}
|
||||
|
@ -36,9 +32,7 @@ func (s *Store) VisitAll(cb func(k string, v interface{})) {
|
|||
// Get returns the value of an entry by its key
|
||||
func (s *Store) Get(key string) interface{} {
|
||||
Provider.Update(s.sid)
|
||||
s.mu.Lock()
|
||||
if value, found := s.values[key]; found {
|
||||
s.mu.Unlock()
|
||||
return value
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
|
|
@ -81,15 +81,11 @@ func (s *Store) update() {
|
|||
|
||||
// GetAll returns all values
|
||||
func (s *Store) GetAll() map[string]interface{} {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.values
|
||||
}
|
||||
|
||||
// VisitAll loop each one entry and calls the callback function func(key,value)
|
||||
func (s *Store) VisitAll(cb func(k string, v interface{})) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for key := range s.values {
|
||||
cb(key, s.values[key])
|
||||
}
|
||||
|
@ -98,12 +94,10 @@ func (s *Store) VisitAll(cb func(k string, v interface{})) {
|
|||
// Get returns the value of an entry by its key
|
||||
func (s *Store) Get(key string) interface{} {
|
||||
Provider.Update(s.sid)
|
||||
s.mu.Lock()
|
||||
if value, found := s.values[key]; found {
|
||||
s.mu.Unlock()
|
||||
return value
|
||||
}
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
120
sessions_test.go
120
sessions_test.go
|
@ -1,120 +0,0 @@
|
|||
package iris
|
||||
|
||||
// Contains tests for sessions(sessions package) & flash messages(context)
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSessions(t *testing.T) {
|
||||
|
||||
values := map[string]interface{}{
|
||||
"Name": "iris",
|
||||
"Months": "4",
|
||||
"Secret": "dsads£2132215£%%Ssdsa",
|
||||
}
|
||||
|
||||
initDefault()
|
||||
Config.Sessions.Cookie = "mycustomsessionid"
|
||||
|
||||
writeValues := func(ctx *Context) {
|
||||
sessValues := ctx.Session().GetAll()
|
||||
ctx.JSON(StatusOK, sessValues)
|
||||
}
|
||||
|
||||
if testEnableSubdomain {
|
||||
Party(testSubdomain+".").Get("/get", func(ctx *Context) {
|
||||
writeValues(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
Post("set", func(ctx *Context) {
|
||||
vals := make(map[string]interface{}, 0)
|
||||
if err := ctx.ReadJSON(&vals); err != nil {
|
||||
t.Fatalf("Cannot readjson. Trace %s", err.Error())
|
||||
}
|
||||
for k, v := range vals {
|
||||
ctx.Session().Set(k, v)
|
||||
}
|
||||
})
|
||||
|
||||
Get("/get", func(ctx *Context) {
|
||||
writeValues(ctx)
|
||||
})
|
||||
|
||||
Get("/clear", func(ctx *Context) {
|
||||
ctx.Session().Clear()
|
||||
writeValues(ctx)
|
||||
})
|
||||
|
||||
Get("/destroy", func(ctx *Context) {
|
||||
ctx.SessionDestroy()
|
||||
writeValues(ctx)
|
||||
// the cookie and all values should be empty
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
|
||||
e.POST("/set").WithJSON(values).Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
e.GET("/get").Expect().Status(StatusOK).JSON().Object().Equal(values)
|
||||
if testEnableSubdomain {
|
||||
es := subdomainTester(e)
|
||||
es.Request("GET", "/get").Expect().Status(StatusOK).JSON().Object().Equal(values)
|
||||
}
|
||||
|
||||
// test destory which also clears first
|
||||
d := e.GET("/destroy").Expect().Status(StatusOK)
|
||||
d.JSON().Object().Empty()
|
||||
d.Cookies().ContainsOnly(Config.Sessions.Cookie)
|
||||
// set and clear again
|
||||
e.POST("/set").WithJSON(values).Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
e.GET("/clear").Expect().Status(StatusOK).JSON().Object().Empty()
|
||||
}
|
||||
|
||||
func FlashMessagesTest(t *testing.T) {
|
||||
initDefault()
|
||||
values := map[string]string{"name": "kataras", "package": "iris"}
|
||||
|
||||
Put("/set", func(ctx *Context) {
|
||||
for k, v := range values {
|
||||
ctx.SetFlash(k, v)
|
||||
}
|
||||
})
|
||||
|
||||
//we don't get the flash so on the next request the flash messages should be available.
|
||||
Get("/get_no_getflash", func(ctx *Context) {})
|
||||
|
||||
Get("/get", func(ctx *Context) {
|
||||
// one time one handler
|
||||
kv := make(map[string]string)
|
||||
for k := range values {
|
||||
kv[k], _ = ctx.GetFlash(k)
|
||||
}
|
||||
//second time on the same handler
|
||||
for k := range values {
|
||||
kv[k], _ = ctx.GetFlash(k)
|
||||
}
|
||||
|
||||
}, func(ctx *Context) {
|
||||
// third time on a next handler
|
||||
// test the if next handler has access to them(must) because flash are request lifetime now.
|
||||
kv := make(map[string]string)
|
||||
for k := range values {
|
||||
kv[k], _ = ctx.GetFlash(k)
|
||||
}
|
||||
// print them to the client for test the response also
|
||||
ctx.JSON(StatusOK, kv)
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
e.PUT("/set").Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
// just a request which does not use the flash message, so flash messages should be available on the next request
|
||||
e.GET("/get_no_getflash").Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
e.GET("/get").Expect().Status(StatusOK).JSON().Object().Equal(values)
|
||||
// second request ,the flash messages here should be not available and cookie has been removed
|
||||
// (the true is that the cookie is removed from the first GetFlash, but is available though the whole request saved on context's values for faster get, keep that secret!)*
|
||||
g := e.GET("/get").Expect().Status(StatusOK)
|
||||
g.JSON().Object().Empty()
|
||||
g.Cookies().Empty()
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user