Fasthttp seems have little bug with headers, so make a VisitAllCookies function and GetFlashes completed- tests added also

This commit is contained in:
Makis Maropoulos 2016-07-07 00:25:50 +02:00
parent 2cc75817b7
commit 01914b6c37
9 changed files with 502 additions and 260 deletions

View File

@ -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

View File

@ -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}
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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()
}

View File

@ -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{

View File

@ -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()

View File

@ -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
}

View File

@ -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()
}