Update to 4.6.0, read HISTORY.md

https://github.com/kataras/iris/blob/master/HISTORY.md
This commit is contained in:
Gerasimos Maropoulos 2016-10-13 17:25:01 +03:00
parent cd8a21c074
commit 122aab4083
11 changed files with 650 additions and 463 deletions

View File

@ -3,6 +3,79 @@
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`. **How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`.
## 4.5.2/.3 -> 4.6.0
### This update affects only testers who used `iris.Tester` at the past.
- **FIX**: httptest flags caused by httpexpect which used to help you with tests inside **old** func `iris.Tester` as reported [here]( https://github.com/kataras/iris/issues/337#issuecomment-253429976)
- **NEW**: `iris.ResetDefault()` func which resets the default iris instance which is the station for the most part of the public/package API
- **NEW**: package `httptest` with configuration which can be passed per 'tester' instead of iris instance( this is very helpful for testers)
- **CHANGED**: All tests are now converted for 'white-box' testing, means that tests now have package named: `iris_test` instead of `iris` in the same main directory.
- **CHANGED**: `iris.Tester` moved to `httptest.New` which lives inside the new `/kataras/iris/httptest` package, so:
**old**
```go
import (
"github.com/kataras/iris"
"testing"
)
func MyTest(t *testing.T) {
iris.Get("/mypath", func(ctx *iris.Context){
ctx.Write("my body")
})
// with configs: iris.Config.Tester.ExplicitURL/Debug = true
e:= iris.Tester(t)
e.GET("/mypath").Expect().Status(iris.StatusOK).Body().Equal("my body")
}
```
**used that instead/new**
```go
import (
"github.com/kataras/iris/httptest"
"github.com/kataras/iris"
"testing"
)
func MyTest(t *testing.T) {
// make sure that you reset your default station if you don't use the form of app := iris.New()
iris.ResetDefault()
iris.Get("/mypath", func(ctx *iris.Context){
ctx.Write("my body")
})
e:= httptest.New(iris.Default, t)
// with configs: e:= httptest.New(iris.Default, t, httptest.ExplicitURL(true), httptest.Debug(true))
e.GET("/mypath").Expect().Status(iris.StatusOK).Body().Equal("my body")
}
```
Finally, some plugins container's additions:
- **NEW**: `iris.Plugins.Len()` func which returns the length of the current activated plugins in the default station
- **NEW**: `iris.Plugins.Fired("event") int` func which returns how much times and from how many plugins a particular event type is fired, event types are: `"prelookup", "prebuild", "prelisten", "postlisten", "preclose", "predownload"`
- **NEW**: `iris.Plugins.PreLookupFired() bool` func which returns true if `PreLookup` fired at least one time
- **NEW**: `iris.Plugins.PreBuildFired() bool` func which returns true if `PreBuild` fired at least one time
- **NEW**: `iris.Plugins.PreListenFired() bool` func which returns true if `PreListen/PreListenParallel` fired at least one time
- **NEW**: `iris.Plugins.PostListenFired() bool` func which returns true if `PostListen` fired at least one time
- **NEW**: `iris.Plugins.PreCloseFired() bool` func which returns true if `PreClose` fired at least one time
- **NEW**: `iris.Plugins.PreDownloadFired() bool` func which returns true if `PreDownload` fired at least one time
## 4.5.1 -> 4.5.2 ## 4.5.1 -> 4.5.2
- **Feature request**: I never though that it will be easier for users to catch 405 instead of simple 404, I though that will make your life harder, but it's requested by the Community [here](https://github.com/kataras/iris/issues/469), so I did my duty. Enable firing Status Method Not Allowed (405) with a simple configuration field: `iris.Config.FireMethodNotAllowed=true` or `iris.Set(iris.OptionFireMethodNotAllowed(true))` or `app := iris.New(iris.Configuration{FireMethodNotAllowed:true})`. A trivial, test example can be shown here: - **Feature request**: I never though that it will be easier for users to catch 405 instead of simple 404, I though that will make your life harder, but it's requested by the Community [here](https://github.com/kataras/iris/issues/469), so I did my duty. Enable firing Status Method Not Allowed (405) with a simple configuration field: `iris.Config.FireMethodNotAllowed=true` or `iris.Set(iris.OptionFireMethodNotAllowed(true))` or `app := iris.New(iris.Configuration{FireMethodNotAllowed:true})`. A trivial, test example can be shown here:

View File

@ -207,10 +207,6 @@ type Configuration struct {
// Websocket contains the configs for Websocket's server integration // Websocket contains the configs for Websocket's server integration
Websocket WebsocketConfiguration Websocket WebsocketConfiguration
// Tester contains the configs for the test framework, so far we have only one because all test framework's configs are setted by the iris itself
// You can find example on the https://github.com/kataras/iris/glob/master/context_test.go
Tester TesterConfiguration
// Other are the custom, dynamic options, can be empty // Other are the custom, dynamic options, can be empty
// this fill used only by you to set any app's options you want // this fill used only by you to set any app's options you want
// for each of an Iris instance // for each of an Iris instance
@ -547,7 +543,6 @@ func DefaultConfiguration() Configuration {
Gzip: false, Gzip: false,
Sessions: DefaultSessionsConfiguration(), Sessions: DefaultSessionsConfiguration(),
Websocket: DefaultWebsocketConfiguration(), Websocket: DefaultWebsocketConfiguration(),
Tester: DefaultTesterConfiguration(),
Other: options.Options{}, Other: options.Options{},
} }
} }
@ -820,38 +815,6 @@ func DefaultWebsocketConfiguration() WebsocketConfiguration {
} }
} }
// TesterConfiguration configuration used inside main config field 'Tester'
type TesterConfiguration struct {
// ExplicitURL If true then the url (should) be prepended manually, useful when want to test subdomains
// Default is false
ExplicitURL bool
// Debug if true then debug messages from the httpexpect will be shown when a test runs
// Default is false
Debug bool
}
var (
// OptionTesterExplicitURL If true then the url (should) be prepended manually, useful when want to test subdomains
// Default is false
OptionTesterExplicitURL = func(val bool) OptionSet {
return func(c *Configuration) {
c.Tester.ExplicitURL = val
}
}
// OptionTesterDebug if true then debug messages from the httpexpect will be shown when a test runs
// Default is false
OptionTesterDebug = func(val bool) OptionSet {
return func(c *Configuration) {
c.Tester.Debug = val
}
}
)
// DefaultTesterConfiguration returns the default configuration for a tester
func DefaultTesterConfiguration() TesterConfiguration {
return TesterConfiguration{ExplicitURL: false, Debug: false}
}
// Default values for base Server conf // Default values for base Server conf
const ( const (
// DefaultServerHostname returns the default hostname which is 0.0.0.0 // DefaultServerHostname returns the default hostname which is 0.0.0.0

View File

@ -1,6 +1,8 @@
package iris // Black-box Testing
package iris_test
import ( import (
"github.com/kataras/iris"
"reflect" "reflect"
"testing" "testing"
) )
@ -8,9 +10,9 @@ import (
// go test -v -run TestConfig* // go test -v -run TestConfig*
func TestConfigStatic(t *testing.T) { func TestConfigStatic(t *testing.T) {
def := DefaultConfiguration() def := iris.DefaultConfiguration()
api := New(def) api := iris.New(def)
afterNew := *api.Config afterNew := *api.Config
if !reflect.DeepEqual(def, afterNew) { if !reflect.DeepEqual(def, afterNew) {
@ -23,7 +25,7 @@ func TestConfigStatic(t *testing.T) {
t.Fatalf("Configuration should be not equal, got: %#v", afterNew) t.Fatalf("Configuration should be not equal, got: %#v", afterNew)
} }
api = New(Configuration{IsDevelopment: true}) api = iris.New(iris.Configuration{IsDevelopment: true})
afterNew = *api.Config afterNew = *api.Config
@ -31,7 +33,7 @@ func TestConfigStatic(t *testing.T) {
t.Fatalf("Passing a Configuration field as Option fails, expected IsDevelopment to be true but was false") t.Fatalf("Passing a Configuration field as Option fails, expected IsDevelopment to be true but was false")
} }
api = New() // empty , means defaults so api = iris.New() // empty , means defaults so
if !reflect.DeepEqual(def, *api.Config) { if !reflect.DeepEqual(def, *api.Config) {
t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, *api.Config) t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, *api.Config)
} }
@ -41,7 +43,7 @@ func TestConfigOptions(t *testing.T) {
charset := "MYCHARSET" charset := "MYCHARSET"
dev := true dev := true
api := New(OptionCharset(charset), OptionIsDevelopment(dev)) api := iris.New(iris.OptionCharset(charset), iris.OptionIsDevelopment(dev))
if got := api.Config.Charset; got != charset { if got := api.Config.Charset; got != charset {
t.Fatalf("Expected configuration Charset to be: %s but got: %s", charset, got) t.Fatalf("Expected configuration Charset to be: %s but got: %s", charset, got)
@ -53,7 +55,7 @@ func TestConfigOptions(t *testing.T) {
// now check if other default values are setted (should be setted automatically) // now check if other default values are setted (should be setted automatically)
expected := DefaultConfiguration() expected := iris.DefaultConfiguration()
expected.Charset = charset expected.Charset = charset
expected.IsDevelopment = dev expected.IsDevelopment = dev
@ -69,9 +71,9 @@ func TestConfigOptionsDeep(t *testing.T) {
dev := true dev := true
vhost := "mydomain.com" vhost := "mydomain.com"
// first session, after charset,dev and profilepath, no canonical order. // first session, after charset,dev and profilepath, no canonical order.
api := New(OptionSessionsCookie(cookiename), OptionCharset(charset), OptionIsDevelopment(dev), OptionVHost(vhost)) api := iris.New(iris.OptionSessionsCookie(cookiename), iris.OptionCharset(charset), iris.OptionIsDevelopment(dev), iris.OptionVHost(vhost))
expected := DefaultConfiguration() expected := iris.DefaultConfiguration()
expected.Sessions.Cookie = cookiename expected.Sessions.Cookie = cookiename
expected.Charset = charset expected.Charset = charset
expected.IsDevelopment = dev expected.IsDevelopment = dev

View File

@ -96,10 +96,10 @@ type (
Params PathParameters Params PathParameters
framework *Framework framework *Framework
//keep track all registed middleware (handlers) //keep track all registed middleware (handlers)
middleware Middleware Middleware Middleware // exported because is useful for debugging
session sessions.Session session sessions.Session
// pos is the position number of the Context, look .Next to understand // Pos is the position number of the Context, look .Next to understand
pos uint8 Pos uint8 // exported because is useful for debugging
} }
) )
@ -110,37 +110,37 @@ func (ctx *Context) GetRequestCtx() *fasthttp.RequestCtx {
// Do calls the first handler only, it's like Next with negative pos, used only on Router&MemoryRouter // Do calls the first handler only, it's like Next with negative pos, used only on Router&MemoryRouter
func (ctx *Context) Do() { func (ctx *Context) Do() {
ctx.pos = 0 ctx.Pos = 0
ctx.middleware[0].Serve(ctx) ctx.Middleware[0].Serve(ctx)
} }
// Next calls all the next handler from the middleware stack, it used inside a middleware // Next calls all the next handler from the middleware stack, it used inside a middleware
func (ctx *Context) Next() { func (ctx *Context) Next() {
//set position to the next //set position to the next
ctx.pos++ ctx.Pos++
midLen := uint8(len(ctx.middleware)) midLen := uint8(len(ctx.Middleware))
//run the next //run the next
if ctx.pos < midLen { if ctx.Pos < midLen {
ctx.middleware[ctx.pos].Serve(ctx) ctx.Middleware[ctx.Pos].Serve(ctx)
} }
} }
// StopExecution just sets the .pos to 255 in order to not move to the next middlewares(if any) // StopExecution just sets the .pos to 255 in order to not move to the next middlewares(if any)
func (ctx *Context) StopExecution() { func (ctx *Context) StopExecution() {
ctx.pos = stopExecutionPosition ctx.Pos = stopExecutionPosition
} }
// //
// IsStopped checks and returns true if the current position of the Context is 255, means that the StopExecution has called // IsStopped checks and returns true if the current position of the Context is 255, means that the StopExecution has called
func (ctx *Context) IsStopped() bool { func (ctx *Context) IsStopped() bool {
return ctx.pos == stopExecutionPosition return ctx.Pos == stopExecutionPosition
} }
// GetHandlerName as requested returns the stack-name of the function which the Middleware is setted from // GetHandlerName as requested returns the stack-name of the function which the Middleware is setted from
func (ctx *Context) GetHandlerName() string { func (ctx *Context) GetHandlerName() string {
return runtime.FuncForPC(reflect.ValueOf(ctx.middleware[len(ctx.middleware)-1]).Pointer()).Name() return runtime.FuncForPC(reflect.ValueOf(ctx.Middleware[len(ctx.Middleware)-1]).Pointer()).Name()
} }
/* Request */ /* Request */

View File

@ -1,4 +1,5 @@
package iris // Black-box Testing
package iris_test
/* /*
The most part of the context covered, The most part of the context covered,
@ -14,30 +15,32 @@ import (
"encoding/json" "encoding/json"
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"github.com/kataras/iris"
"github.com/kataras/iris/httptest"
"github.com/valyala/fasthttp"
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/valyala/fasthttp"
) )
// White-box testing *
func TestContextDoNextStop(t *testing.T) { func TestContextDoNextStop(t *testing.T) {
var context Context var context iris.Context
ok := false ok := false
afterStop := false afterStop := false
context.middleware = Middleware{HandlerFunc(func(*Context) { context.Middleware = iris.Middleware{iris.HandlerFunc(func(*iris.Context) {
ok = true ok = true
}), HandlerFunc(func(*Context) { }), iris.HandlerFunc(func(*iris.Context) {
ok = true ok = true
}), HandlerFunc(func(*Context) { }), iris.HandlerFunc(func(*iris.Context) {
// this will never execute // this will never execute
afterStop = true afterStop = true
})} })}
context.Do() context.Do()
if context.pos != 0 { if context.Pos != 0 {
t.Fatalf("Expecting position 0 for context's middleware but we got: %d", context.pos) t.Fatalf("Expecting position 0 for context's middleware but we got: %d", context.Pos)
} }
if !ok { if !ok {
t.Fatalf("Unexpected behavior, first context's middleware didn't executed") t.Fatalf("Unexpected behavior, first context's middleware didn't executed")
@ -46,16 +49,16 @@ func TestContextDoNextStop(t *testing.T) {
context.Next() context.Next()
if int(context.pos) != 1 { if int(context.Pos) != 1 {
t.Fatalf("Expecting to have position %d but we got: %d", 1, context.pos) t.Fatalf("Expecting to have position %d but we got: %d", 1, context.Pos)
} }
if !ok { if !ok {
t.Fatalf("Next context's middleware didn't executed") t.Fatalf("Next context's middleware didn't executed")
} }
context.StopExecution() context.StopExecution()
if context.pos != stopExecutionPosition { if context.Pos != 255 {
t.Fatalf("Context's StopExecution didn't worked, we expected to have position %d but we got %d", stopExecutionPosition, context.pos) t.Fatalf("Context's StopExecution didn't worked, we expected to have position %d but we got %d", 255, context.Pos)
} }
if !context.IsStopped() { if !context.IsStopped() {
@ -69,13 +72,14 @@ func TestContextDoNextStop(t *testing.T) {
} }
} }
// White-box testing *
func TestContextParams(t *testing.T) { func TestContextParams(t *testing.T) {
var context Context var context iris.Context
params := PathParameters{ params := iris.PathParameters{
PathParameter{Key: "testkey", Value: "testvalue"}, iris.PathParameter{Key: "testkey", Value: "testvalue"},
PathParameter{Key: "testkey2", Value: "testvalue2"}, iris.PathParameter{Key: "testkey2", Value: "testvalue2"},
PathParameter{Key: "id", Value: "3"}, iris.PathParameter{Key: "id", Value: "3"},
PathParameter{Key: "bigint", Value: "548921854390354"}, iris.PathParameter{Key: "bigint", Value: "548921854390354"},
} }
context.Params = params context.Params = params
@ -104,94 +108,94 @@ func TestContextParams(t *testing.T) {
// end-to-end test now, note that we will not test the whole mux here, this happens on http_test.go // end-to-end test now, note that we will not test the whole mux here, this happens on http_test.go
initDefault() iris.ResetDefault()
expectedParamsStr := "param1=myparam1,param2=myparam2,param3=myparam3afterstatic,anything=/andhere/anything/you/like" expectedParamsStr := "param1=myparam1,param2=myparam2,param3=myparam3afterstatic,anything=/andhere/anything/you/like"
Get("/path/:param1/:param2/staticpath/:param3/*anything", func(ctx *Context) { iris.Get("/path/:param1/:param2/staticpath/:param3/*anything", func(ctx *iris.Context) {
paramsStr := ctx.Params.String() paramsStr := ctx.Params.String()
ctx.Write(paramsStr) ctx.Write(paramsStr)
}) })
Tester(t).GET("/path/myparam1/myparam2/staticpath/myparam3afterstatic/andhere/anything/you/like").Expect().Status(StatusOK).Body().Equal(expectedParamsStr) httptest.New(iris.Default, t).GET("/path/myparam1/myparam2/staticpath/myparam3afterstatic/andhere/anything/you/like").Expect().Status(iris.StatusOK).Body().Equal(expectedParamsStr)
} }
func TestContextURLParams(t *testing.T) { func TestContextURLParams(t *testing.T) {
initDefault() iris.ResetDefault()
passedParams := map[string]string{"param1": "value1", "param2": "value2"} passedParams := map[string]string{"param1": "value1", "param2": "value2"}
Get("/", func(ctx *Context) { iris.Get("/", func(ctx *iris.Context) {
params := ctx.URLParams() params := ctx.URLParams()
ctx.JSON(StatusOK, params) ctx.JSON(iris.StatusOK, params)
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/").WithQueryObject(passedParams).Expect().Status(StatusOK).JSON().Equal(passedParams) e.GET("/").WithQueryObject(passedParams).Expect().Status(iris.StatusOK).JSON().Equal(passedParams)
} }
// hoststring returns the full host, will return the HOST:IP // hoststring returns the full host, will return the HOST:IP
func TestContextHostString(t *testing.T) { func TestContextHostString(t *testing.T) {
initDefault() iris.ResetDefault()
Default.Config.VHost = "0.0.0.0:8080" iris.Default.Config.VHost = "0.0.0.0:8080"
Get("/", func(ctx *Context) { iris.Get("/", func(ctx *iris.Context) {
ctx.Write(ctx.HostString()) ctx.Write(ctx.HostString())
}) })
Get("/wrong", func(ctx *Context) { iris.Get("/wrong", func(ctx *iris.Context) {
ctx.Write(ctx.HostString() + "w") ctx.Write(ctx.HostString() + "w")
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/").Expect().Status(StatusOK).Body().Equal(Default.Config.VHost) e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(iris.Default.Config.VHost)
e.GET("/wrong").Expect().Body().NotEqual(Default.Config.VHost) e.GET("/wrong").Expect().Body().NotEqual(iris.Default.Config.VHost)
} }
// VirtualHostname returns the hostname only, // 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 // 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) { func TestContextVirtualHostName(t *testing.T) {
initDefault() iris.ResetDefault()
vhost := "mycustomvirtualname.com" vhost := "mycustomvirtualname.com"
Default.Config.VHost = vhost + ":8080" iris.Default.Config.VHost = vhost + ":8080"
Get("/", func(ctx *Context) { iris.Get("/", func(ctx *iris.Context) {
ctx.Write(ctx.VirtualHostname()) ctx.Write(ctx.VirtualHostname())
}) })
Get("/wrong", func(ctx *Context) { iris.Get("/wrong", func(ctx *iris.Context) {
ctx.Write(ctx.VirtualHostname() + "w") ctx.Write(ctx.VirtualHostname() + "w")
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/").Expect().Status(StatusOK).Body().Equal(vhost) e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(vhost)
e.GET("/wrong").Expect().Body().NotEqual(vhost) e.GET("/wrong").Expect().Body().NotEqual(vhost)
} }
func TestContextFormValueString(t *testing.T) { func TestContextFormValueString(t *testing.T) {
initDefault() iris.ResetDefault()
var k, v string var k, v string
k = "postkey" k = "postkey"
v = "postvalue" v = "postvalue"
Post("/", func(ctx *Context) { iris.Post("/", func(ctx *iris.Context) {
ctx.Write(k + "=" + ctx.FormValueString(k)) ctx.Write(k + "=" + ctx.FormValueString(k))
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.POST("/").WithFormField(k, v).Expect().Status(StatusOK).Body().Equal(k + "=" + v) e.POST("/").WithFormField(k, v).Expect().Status(iris.StatusOK).Body().Equal(k + "=" + v)
} }
func TestContextSubdomain(t *testing.T) { func TestContextSubdomain(t *testing.T) {
initDefault() iris.ResetDefault()
Default.Config.VHost = "mydomain.com:9999" iris.Default.Config.VHost = "mydomain.com:9999"
//Default.Config.Tester.ListeningAddr = "mydomain.com:9999" //Default.Config.Tester.ListeningAddr = "mydomain.com:9999"
// Default.Config.Tester.ExplicitURL = true // Default.Config.Tester.ExplicitURL = true
Party("mysubdomain.").Get("/mypath", func(ctx *Context) { iris.Party("mysubdomain.").Get("/mypath", func(ctx *iris.Context) {
ctx.Write(ctx.Subdomain()) ctx.Write(ctx.Subdomain())
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusNotFound) e.GET("/").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(iris.StatusNotFound)
e.GET("/mypath").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusOK).Body().Equal("mysubdomain") e.GET("/mypath").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(iris.StatusOK).Body().Equal("mysubdomain")
//e.GET("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusNotFound) //e.GET("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusNotFound)
//e.GET("http://mysubdomain.mydomain.com:9999/mypath").Expect().Status(StatusOK).Body().Equal("mysubdomain") //e.GET("http://mysubdomain.mydomain.com:9999/mypath").Expect().Status(iris.StatusOK).Body().Equal("mysubdomain")
} }
type testBinderData struct { type testBinderData struct {
@ -210,53 +214,53 @@ type testBinderXMLData struct {
} }
func TestContextReadForm(t *testing.T) { func TestContextReadForm(t *testing.T) {
initDefault() iris.ResetDefault()
Post("/form", func(ctx *Context) { iris.Post("/form", func(ctx *iris.Context) {
obj := testBinderData{} obj := testBinderData{}
err := ctx.ReadForm(&obj) err := ctx.ReadForm(&obj)
if err != nil { if err != nil {
t.Fatalf("Error when parsing the FORM: %s", err.Error()) t.Fatalf("Error when parsing the FORM: %s", err.Error())
} }
ctx.JSON(StatusOK, obj) ctx.JSON(iris.StatusOK, obj)
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
passed := map[string]interface{}{"Username": "myusername", "Mail": "mymail@iris-go.com", "mydata": url.Values{"[0]": []string{"mydata1"}, passed := map[string]interface{}{"Username": "myusername", "Mail": "mymail@iris-go.com", "mydata": url.Values{"[0]": []string{"mydata1"},
"[1]": []string{"mydata2"}}} "[1]": []string{"mydata2"}}}
expectedObject := testBinderData{Username: "myusername", Mail: "mymail@iris-go.com", Data: []string{"mydata1", "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) e.POST("/form").WithForm(passed).Expect().Status(iris.StatusOK).JSON().Object().Equal(expectedObject)
} }
func TestContextReadJSON(t *testing.T) { func TestContextReadJSON(t *testing.T) {
initDefault() iris.ResetDefault()
Post("/json", func(ctx *Context) { iris.Post("/json", func(ctx *iris.Context) {
obj := testBinderData{} obj := testBinderData{}
err := ctx.ReadJSON(&obj) err := ctx.ReadJSON(&obj)
if err != nil { if err != nil {
t.Fatalf("Error when parsing the JSON body: %s", err.Error()) t.Fatalf("Error when parsing the JSON body: %s", err.Error())
} }
ctx.JSON(StatusOK, obj) ctx.JSON(iris.StatusOK, obj)
}) })
Post("/json_pointer", func(ctx *Context) { iris.Post("/json_pointer", func(ctx *iris.Context) {
obj := &testBinderData{} obj := &testBinderData{}
err := ctx.ReadJSON(obj) err := ctx.ReadJSON(obj)
if err != nil { if err != nil {
t.Fatalf("Error when parsing the JSON body: %s", err.Error()) t.Fatalf("Error when parsing the JSON body: %s", err.Error())
} }
ctx.JSON(StatusOK, obj) ctx.JSON(iris.StatusOK, obj)
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
passed := map[string]interface{}{"Username": "myusername", "Mail": "mymail@iris-go.com", "mydata": []string{"mydata1", "mydata2"}} 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"}} 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) e.POST("/json").WithJSON(passed).Expect().Status(iris.StatusOK).JSON().Object().Equal(expectedObject)
e.POST("/json_pointer").WithJSON(passed).Expect().Status(StatusOK).JSON().Object().Equal(expectedObject) e.POST("/json_pointer").WithJSON(passed).Expect().Status(iris.StatusOK).JSON().Object().Equal(expectedObject)
} }
type testJSONBinderDataWithDecoder struct { type testJSONBinderDataWithDecoder struct {
@ -274,57 +278,57 @@ func (tj *testJSONBinderDataWithDecoder) Decode(data []byte) error {
} }
func TestContextReadJSONWithDecoder(t *testing.T) { func TestContextReadJSONWithDecoder(t *testing.T) {
initDefault() iris.ResetDefault()
Post("/json_should_error", func(ctx *Context) { iris.Post("/json_should_error", func(ctx *iris.Context) {
obj := testJSONBinderDataWithDecoder{shouldError: true} obj := testJSONBinderDataWithDecoder{shouldError: true}
err := ctx.ReadJSON(&obj) err := ctx.ReadJSON(&obj)
if err == nil { if err == nil {
t.Fatalf("Should prompted for error 'Should error' but not error returned from the custom decoder!") t.Fatalf("Should prompted for error 'Should error' but not error returned from the custom decoder!")
} }
ctx.Write(err.Error()) ctx.Write(err.Error())
ctx.SetStatusCode(StatusOK) ctx.SetStatusCode(iris.StatusOK)
}) })
Post("/json", func(ctx *Context) { iris.Post("/json", func(ctx *iris.Context) {
obj := testJSONBinderDataWithDecoder{} obj := testJSONBinderDataWithDecoder{}
err := ctx.ReadJSON(&obj) err := ctx.ReadJSON(&obj)
if err != nil { if err != nil {
t.Fatalf("Error when parsing the JSON body: %s", err.Error()) t.Fatalf("Error when parsing the JSON body: %s", err.Error())
} }
ctx.JSON(StatusOK, obj) ctx.JSON(iris.StatusOK, obj)
}) })
Post("/json_pointer", func(ctx *Context) { iris.Post("/json_pointer", func(ctx *iris.Context) {
obj := &testJSONBinderDataWithDecoder{} obj := &testJSONBinderDataWithDecoder{}
err := ctx.ReadJSON(obj) err := ctx.ReadJSON(obj)
if err != nil { if err != nil {
t.Fatalf("Error when parsing the JSON body: %s", err.Error()) t.Fatalf("Error when parsing the JSON body: %s", err.Error())
} }
ctx.JSON(StatusOK, obj) ctx.JSON(iris.StatusOK, obj)
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
passed := map[string]interface{}{"Username": "kataras", "Mail": "mymail@iris-go.com", "mydata": []string{"mydata1", "mydata2"}} passed := map[string]interface{}{"Username": "kataras", "Mail": "mymail@iris-go.com", "mydata": []string{"mydata1", "mydata2"}}
expectedObject := testJSONBinderDataWithDecoder{Username: "kataras", Mail: "mymail@iris-go.com", Data: []string{"mydata1", "mydata2"}} expectedObject := testJSONBinderDataWithDecoder{Username: "kataras", Mail: "mymail@iris-go.com", Data: []string{"mydata1", "mydata2"}}
e.POST("/json_should_error").WithJSON(passed).Expect().Status(StatusOK).Body().Equal("Should error") e.POST("/json_should_error").WithJSON(passed).Expect().Status(iris.StatusOK).Body().Equal("Should error")
e.POST("/json").WithJSON(passed).Expect().Status(StatusOK).JSON().Object().Equal(expectedObject) e.POST("/json").WithJSON(passed).Expect().Status(iris.StatusOK).JSON().Object().Equal(expectedObject)
e.POST("/json_pointer").WithJSON(passed).Expect().Status(StatusOK).JSON().Object().Equal(expectedObject) e.POST("/json_pointer").WithJSON(passed).Expect().Status(iris.StatusOK).JSON().Object().Equal(expectedObject)
} // no need for xml, it's exact the same. } // no need for xml, it's exact the same.
func TestContextReadXML(t *testing.T) { func TestContextReadXML(t *testing.T) {
initDefault() iris.ResetDefault()
Post("/xml", func(ctx *Context) { iris.Post("/xml", func(ctx *iris.Context) {
obj := testBinderXMLData{} obj := testBinderXMLData{}
err := ctx.ReadXML(&obj) err := ctx.ReadXML(&obj)
if err != nil { if err != nil {
t.Fatalf("Error when parsing the XML body: %s", err.Error()) t.Fatalf("Error when parsing the XML body: %s", err.Error())
} }
ctx.XML(StatusOK, obj) ctx.XML(iris.StatusOK, obj)
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
expectedObj := testBinderXMLData{ expectedObj := testBinderXMLData{
XMLName: xml.Name{Local: "info", Space: "info"}, XMLName: xml.Name{Local: "info", Space: "info"},
FirstAttr: "this is the first attr", FirstAttr: "this is the first attr",
@ -335,23 +339,23 @@ func TestContextReadXML(t *testing.T) {
} }
// so far no WithXML or .XML like WithJSON and .JSON on httpexpect I added a feature request as post issue and we're waiting // 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>` 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) e.POST("/xml").WithText(expectedBody).Expect().Status(iris.StatusOK).Body().Equal(expectedBody)
} }
// TestContextRedirectTo tests the named route redirect action // TestContextRedirectTo tests the named route redirect action
func TestContextRedirectTo(t *testing.T) { func TestContextRedirectTo(t *testing.T) {
initDefault() iris.ResetDefault()
h := func(ctx *Context) { ctx.Write(ctx.PathString()) } h := func(ctx *iris.Context) { ctx.Write(ctx.PathString()) }
Get("/mypath", h)("my-path") iris.Get("/mypath", h)("my-path")
Get("/mypostpath", h)("my-post-path") iris.Get("/mypostpath", h)("my-post-path")
Get("mypath/with/params/:param1/:param2", func(ctx *Context) { iris.Get("mypath/with/params/:param1/:param2", func(ctx *iris.Context) {
if len(ctx.Params) != 2 { if len(ctx.Params) != 2 {
t.Fatalf("Strange error, expecting parameters to be two but we got: %d", len(ctx.Params)) t.Fatalf("Strange error, expecting parameters to be two but we got: %d", len(ctx.Params))
} }
ctx.Write(ctx.PathString()) ctx.Write(ctx.PathString())
})("my-path-with-params") })("my-path-with-params")
Get("/redirect/to/:routeName/*anyparams", func(ctx *Context) { iris.Get("/redirect/to/:routeName/*anyparams", func(ctx *iris.Context) {
routeName := ctx.Param("routeName") routeName := ctx.Param("routeName")
var args []interface{} var args []interface{}
anyparams := ctx.Param("anyparams") anyparams := ctx.Param("anyparams")
@ -365,25 +369,25 @@ func TestContextRedirectTo(t *testing.T) {
ctx.RedirectTo(routeName, args...) ctx.RedirectTo(routeName, args...)
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/redirect/to/my-path/").Expect().Status(StatusOK).Body().Equal("/mypath") e.GET("/redirect/to/my-path/").Expect().Status(iris.StatusOK).Body().Equal("/mypath")
e.GET("/redirect/to/my-post-path/").Expect().Status(StatusOK).Body().Equal("/mypostpath") e.GET("/redirect/to/my-post-path/").Expect().Status(iris.StatusOK).Body().Equal("/mypostpath")
e.GET("/redirect/to/my-path-with-params/firstparam/secondparam").Expect().Status(StatusOK).Body().Equal("/mypath/with/params/firstparam/secondparam") e.GET("/redirect/to/my-path-with-params/firstparam/secondparam").Expect().Status(iris.StatusOK).Body().Equal("/mypath/with/params/firstparam/secondparam")
} }
func TestContextUserValues(t *testing.T) { func TestContextUserValues(t *testing.T) {
initDefault() iris.ResetDefault()
testCustomObjUserValue := struct{ Name string }{Name: "a name"} 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"}} values := map[string]interface{}{"key1": "value1", "key2": "value2", "key3": 3, "key4": testCustomObjUserValue, "key5": map[string]string{"key": "value"}}
Get("/test", func(ctx *Context) { iris.Get("/test", func(ctx *iris.Context) {
for k, v := range values { for k, v := range values {
ctx.Set(k, v) ctx.Set(k, v)
} }
}, func(ctx *Context) { }, func(ctx *iris.Context) {
for k, v := range values { for k, v := range values {
userValue := ctx.Get(k) userValue := ctx.Get(k)
if userValue != v { if userValue != v {
@ -403,21 +407,21 @@ func TestContextUserValues(t *testing.T) {
} }
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/test").Expect().Status(StatusOK) e.GET("/test").Expect().Status(iris.StatusOK)
} }
func TestContextCookieSetGetRemove(t *testing.T) { func TestContextCookieSetGetRemove(t *testing.T) {
initDefault() iris.ResetDefault()
key := "mykey" key := "mykey"
value := "myvalue" value := "myvalue"
Get("/set", func(ctx *Context) { iris.Get("/set", func(ctx *iris.Context) {
ctx.SetCookieKV(key, value) // should return non empty cookies ctx.SetCookieKV(key, value) // should return non empty cookies
}) })
Get("/set_advanced", func(ctx *Context) { iris.Get("/set_advanced", func(ctx *iris.Context) {
c := fasthttp.AcquireCookie() c := fasthttp.AcquireCookie()
c.SetKey(key) c.SetKey(key)
c.SetValue(value) c.SetValue(value)
@ -427,11 +431,11 @@ func TestContextCookieSetGetRemove(t *testing.T) {
fasthttp.ReleaseCookie(c) fasthttp.ReleaseCookie(c)
}) })
Get("/get", func(ctx *Context) { iris.Get("/get", func(ctx *iris.Context) {
ctx.Write(ctx.GetCookie(key)) // should return my value ctx.Write(ctx.GetCookie(key)) // should return my value
}) })
Get("/remove", func(ctx *Context) { iris.Get("/remove", func(ctx *iris.Context) {
ctx.RemoveCookie(key) ctx.RemoveCookie(key)
cookieFound := false cookieFound := false
ctx.VisitAllCookies(func(k, v string) { ctx.VisitAllCookies(func(k, v string) {
@ -443,38 +447,38 @@ func TestContextCookieSetGetRemove(t *testing.T) {
ctx.Write(ctx.GetCookie(key)) // should return "" ctx.Write(ctx.GetCookie(key)) // should return ""
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/set").Expect().Status(StatusOK).Cookies().NotEmpty() e.GET("/set").Expect().Status(iris.StatusOK).Cookies().NotEmpty()
e.GET("/get").Expect().Status(StatusOK).Body().Equal(value) e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal(value)
e.GET("/remove").Expect().Status(StatusOK).Body().Equal("") e.GET("/remove").Expect().Status(iris.StatusOK).Body().Equal("")
// test again with advanced set // test again with advanced set
e.GET("/set_advanced").Expect().Status(StatusOK).Cookies().NotEmpty() e.GET("/set_advanced").Expect().Status(iris.StatusOK).Cookies().NotEmpty()
e.GET("/get").Expect().Status(StatusOK).Body().Equal(value) e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal(value)
e.GET("/remove").Expect().Status(StatusOK).Body().Equal("") e.GET("/remove").Expect().Status(iris.StatusOK).Body().Equal("")
} }
func TestContextFlashMessages(t *testing.T) { func TestContextFlashMessages(t *testing.T) {
initDefault() iris.ResetDefault()
firstKey := "name" firstKey := "name"
lastKey := "package" lastKey := "package"
values := PathParameters{PathParameter{Key: firstKey, Value: "kataras"}, PathParameter{Key: lastKey, Value: "iris"}} values := iris.PathParameters{iris.PathParameter{Key: firstKey, Value: "kataras"}, iris.PathParameter{Key: lastKey, Value: "iris"}}
jsonExpected := map[string]string{firstKey: "kataras", lastKey: "iris"} jsonExpected := map[string]string{firstKey: "kataras", lastKey: "iris"}
// set the flashes, the cookies are filled // set the flashes, the cookies are filled
Put("/set", func(ctx *Context) { iris.Put("/set", func(ctx *iris.Context) {
for _, v := range values { for _, v := range values {
ctx.SetFlash(v.Key, v.Value) ctx.SetFlash(v.Key, v.Value)
} }
}) })
// get the first flash, the next should be available to the next requess // get the first flash, the next should be available to the next requess
Get("/get_first_flash", func(ctx *Context) { iris.Get("/get_first_flash", func(ctx *iris.Context) {
for _, v := range values { for _, v := range values {
val, err := ctx.GetFlash(v.Key) val, err := ctx.GetFlash(v.Key)
if err == nil { if err == nil {
ctx.JSON(StatusOK, map[string]string{v.Key: val}) ctx.JSON(iris.StatusOK, map[string]string{v.Key: val})
} else { } else {
ctx.JSON(StatusOK, nil) // return nil ctx.JSON(iris.StatusOK, nil) // return nil
} }
break break
@ -483,30 +487,30 @@ func TestContextFlashMessages(t *testing.T) {
}) })
// just an empty handler to test if the flashes should remeain to the next if GetFlash/GetFlashes used // 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) { iris.Get("/get_no_getflash", func(ctx *iris.Context) {
}) })
// get the last flash, the next should be available to the next requess // get the last flash, the next should be available to the next requess
Get("/get_last_flash", func(ctx *Context) { iris.Get("/get_last_flash", func(ctx *iris.Context) {
for i, v := range values { for i, v := range values {
if i == len(values)-1 { if i == len(values)-1 {
val, err := ctx.GetFlash(v.Key) val, err := ctx.GetFlash(v.Key)
if err == nil { if err == nil {
ctx.JSON(StatusOK, map[string]string{v.Key: val}) ctx.JSON(iris.StatusOK, map[string]string{v.Key: val})
} else { } else {
ctx.JSON(StatusOK, nil) // return nil ctx.JSON(iris.StatusOK, nil) // return nil
} }
} }
} }
}) })
Get("/get_zero_flashes", func(ctx *Context) { iris.Get("/get_zero_flashes", func(ctx *iris.Context) {
ctx.JSON(StatusOK, ctx.GetFlashes()) // should return nil ctx.JSON(iris.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 // 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) { iris.Get("/get_flash", func(ctx *iris.Context) {
kv := make(map[string]string) kv := make(map[string]string)
for _, v := range values { for _, v := range values {
val, err := ctx.GetFlash(v.Key) val, err := ctx.GetFlash(v.Key)
@ -514,15 +518,15 @@ func TestContextFlashMessages(t *testing.T) {
kv[v.Key] = val kv[v.Key] = val
} }
} }
ctx.JSON(StatusOK, kv) ctx.JSON(iris.StatusOK, kv)
}, func(ctx *Context) { }, func(ctx *iris.Context) {
// at the same request, flashes should be available // at the same request, flashes should be available
if len(ctx.GetFlashes()) == 0 { if len(ctx.GetFlashes()) == 0 {
t.Fatalf("Flashes should be remeain to the whole request lifetime") t.Fatalf("Flashes should be remeain to the whole request lifetime")
} }
}) })
Get("/get_flashes", func(ctx *Context) { iris.Get("/get_flashes", func(ctx *iris.Context) {
// one time one handler, using GetFlashes // one time one handler, using GetFlashes
kv := make(map[string]string) kv := make(map[string]string)
flashes := ctx.GetFlashes() flashes := ctx.GetFlashes()
@ -531,48 +535,48 @@ func TestContextFlashMessages(t *testing.T) {
kv[k], _ = ctx.GetFlash(k) kv[k], _ = ctx.GetFlash(k)
} }
if len(flashes) != len(kv) { if len(flashes) != len(kv) {
ctx.SetStatusCode(StatusNoContent) ctx.SetStatusCode(iris.StatusNoContent)
return return
} }
ctx.Next() ctx.Next()
}, func(ctx *Context) { }, func(ctx *iris.Context) {
// third time on a next handler // third time on a next handler
// test the if next handler has access to them(must) because flash are request lifetime now. // 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 // print them to the client for test the response also
ctx.JSON(StatusOK, ctx.GetFlashes()) ctx.JSON(iris.StatusOK, ctx.GetFlashes())
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.PUT("/set").Expect().Status(StatusOK).Cookies().NotEmpty() e.PUT("/set").Expect().Status(iris.StatusOK).Cookies().NotEmpty()
e.GET("/get_first_flash").Expect().Status(StatusOK).JSON().Object().ContainsKey(firstKey).NotContainsKey(lastKey) e.GET("/get_first_flash").Expect().Status(iris.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 // 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_no_getflash").Expect().Status(iris.StatusOK)
e.GET("/get_last_flash").Expect().Status(StatusOK).JSON().Object().ContainsKey(lastKey).NotContainsKey(firstKey) e.GET("/get_last_flash").Expect().Status(iris.StatusOK).JSON().Object().ContainsKey(lastKey).NotContainsKey(firstKey)
g := e.GET("/get_zero_flashes").Expect().Status(StatusOK) g := e.GET("/get_zero_flashes").Expect().Status(iris.StatusOK)
g.JSON().Null() g.JSON().Null()
g.Cookies().Empty() g.Cookies().Empty()
// set the magain // set the magain
e.PUT("/set").Expect().Status(StatusOK).Cookies().NotEmpty() e.PUT("/set").Expect().Status(iris.StatusOK).Cookies().NotEmpty()
// get them again using GetFlash // get them again using GetFlash
e.GET("/get_flash").Expect().Status(StatusOK).JSON().Object().Equal(jsonExpected) e.GET("/get_flash").Expect().Status(iris.StatusOK).JSON().Object().Equal(jsonExpected)
// this should be empty again // this should be empty again
g = e.GET("/get_zero_flashes").Expect().Status(StatusOK) g = e.GET("/get_zero_flashes").Expect().Status(iris.StatusOK)
g.JSON().Null() g.JSON().Null()
g.Cookies().Empty() g.Cookies().Empty()
//set them again //set them again
e.PUT("/set").Expect().Status(StatusOK).Cookies().NotEmpty() e.PUT("/set").Expect().Status(iris.StatusOK).Cookies().NotEmpty()
// get them again using GetFlashes // get them again using GetFlashes
e.GET("/get_flashes").Expect().Status(StatusOK).JSON().Object().Equal(jsonExpected) e.GET("/get_flashes").Expect().Status(iris.StatusOK).JSON().Object().Equal(jsonExpected)
// this should be empty again // this should be empty again
g = e.GET("/get_zero_flashes").Expect().Status(StatusOK) g = e.GET("/get_zero_flashes").Expect().Status(iris.StatusOK)
g.JSON().Null() g.JSON().Null()
g.Cookies().Empty() g.Cookies().Empty()
// test Get, and get again should return nothing // test Get, and get again should return nothing
e.PUT("/set").Expect().Status(StatusOK).Cookies().NotEmpty() e.PUT("/set").Expect().Status(iris.StatusOK).Cookies().NotEmpty()
e.GET("/get_first_flash").Expect().Status(StatusOK).JSON().Object().ContainsKey(firstKey).NotContainsKey(lastKey) e.GET("/get_first_flash").Expect().Status(iris.StatusOK).JSON().Object().ContainsKey(firstKey).NotContainsKey(lastKey)
g = e.GET("/get_first_flash").Expect().Status(StatusOK) g = e.GET("/get_first_flash").Expect().Status(iris.StatusOK)
g.JSON().Null() g.JSON().Null()
g.Cookies().Empty() g.Cookies().Empty()
} }
@ -585,21 +589,21 @@ func TestContextSessions(t *testing.T) {
"Secret": "dsads£2132215£%%Ssdsa", "Secret": "dsads£2132215£%%Ssdsa",
} }
initDefault() iris.ResetDefault()
Config.Sessions.Cookie = "mycustomsessionid" iris.Default.Config.Sessions.Cookie = "mycustomsessionid"
writeValues := func(ctx *Context) { writeValues := func(ctx *iris.Context) {
sessValues := ctx.Session().GetAll() sessValues := ctx.Session().GetAll()
ctx.JSON(StatusOK, sessValues) ctx.JSON(iris.StatusOK, sessValues)
} }
if testEnableSubdomain { if testEnableSubdomain {
Party(testSubdomain+".").Get("/get", func(ctx *Context) { iris.Party(testSubdomain+".").Get("/get", func(ctx *iris.Context) {
writeValues(ctx) writeValues(ctx)
}) })
} }
Post("set", func(ctx *Context) { iris.Post("set", func(ctx *iris.Context) {
vals := make(map[string]interface{}, 0) vals := make(map[string]interface{}, 0)
if err := ctx.ReadJSON(&vals); err != nil { if err := ctx.ReadJSON(&vals); err != nil {
t.Fatalf("Cannot readjson. Trace %s", err.Error()) t.Fatalf("Cannot readjson. Trace %s", err.Error())
@ -609,44 +613,44 @@ func TestContextSessions(t *testing.T) {
} }
}) })
Get("/get", func(ctx *Context) { iris.Get("/get", func(ctx *iris.Context) {
writeValues(ctx) writeValues(ctx)
}) })
Get("/clear", func(ctx *Context) { iris.Get("/clear", func(ctx *iris.Context) {
ctx.Session().Clear() ctx.Session().Clear()
writeValues(ctx) writeValues(ctx)
}) })
Get("/destroy", func(ctx *Context) { iris.Get("/destroy", func(ctx *iris.Context) {
ctx.SessionDestroy() ctx.SessionDestroy()
writeValues(ctx) writeValues(ctx)
// the cookie and all values should be empty // the cookie and all values should be empty
}) })
// request cookie should be empty // request cookie should be empty
Get("/after_destroy", func(ctx *Context) { iris.Get("/after_destroy", func(ctx *iris.Context) {
}) })
Default.Config.VHost = "mydomain.com" iris.Default.Config.VHost = "mydomain.com"
e := Tester(t) e := httptest.New(iris.Default, t)
e.POST("/set").WithJSON(values).Expect().Status(StatusOK).Cookies().NotEmpty() e.POST("/set").WithJSON(values).Expect().Status(iris.StatusOK).Cookies().NotEmpty()
e.GET("/get").Expect().Status(StatusOK).JSON().Object().Equal(values) e.GET("/get").Expect().Status(iris.StatusOK).JSON().Object().Equal(values)
if testEnableSubdomain { if testEnableSubdomain {
es := subdomainTester(e) es := subdomainTester(e)
es.Request("GET", "/get").Expect().Status(StatusOK).JSON().Object().Equal(values) es.Request("GET", "/get").Expect().Status(iris.StatusOK).JSON().Object().Equal(values)
} }
// test destroy which also clears first // test destroy which also clears first
d := e.GET("/destroy").Expect().Status(StatusOK) d := e.GET("/destroy").Expect().Status(iris.StatusOK)
d.JSON().Null() d.JSON().Null()
// This removed: d.Cookies().Empty(). Reason: // This removed: d.Cookies().Empty(). Reason:
// httpexpect counts the cookies setted or deleted at the response time, but cookie is not removed, to be really removed needs to SetExpire(now-1second) so, // httpexpect counts the cookies setted or deleted at the response time, but cookie is not removed, to be really removed needs to SetExpire(now-1second) so,
// test if the cookies removed on the next request, like the browser's behavior. // test if the cookies removed on the next request, like the browser's behavior.
e.GET("/after_destroy").Expect().Status(StatusOK).Cookies().Empty() e.GET("/after_destroy").Expect().Status(iris.StatusOK).Cookies().Empty()
// set and clear again // set and clear again
e.POST("/set").WithJSON(values).Expect().Status(StatusOK).Cookies().NotEmpty() e.POST("/set").WithJSON(values).Expect().Status(iris.StatusOK).Cookies().NotEmpty()
e.GET("/clear").Expect().Status(StatusOK).JSON().Object().Empty() e.GET("/clear").Expect().Status(iris.StatusOK).JSON().Object().Empty()
} }
type renderTestInformationType struct { type renderTestInformationType struct {
@ -659,7 +663,7 @@ type renderTestInformationType struct {
} }
func TestContextRenderRest(t *testing.T) { func TestContextRenderRest(t *testing.T) {
initDefault() iris.ResetDefault()
dataContents := []byte("Some binary data here.") dataContents := []byte("Some binary data here.")
textContents := "Plain text here" textContents := "Plain text here"
@ -675,59 +679,59 @@ func TestContextRenderRest(t *testing.T) {
} }
markdownContents := "# Hello dynamic markdown from Iris" markdownContents := "# Hello dynamic markdown from Iris"
Get("/data", func(ctx *Context) { iris.Get("/data", func(ctx *iris.Context) {
ctx.Data(StatusOK, dataContents) ctx.Data(iris.StatusOK, dataContents)
}) })
Get("/text", func(ctx *Context) { iris.Get("/text", func(ctx *iris.Context) {
ctx.Text(StatusOK, textContents) ctx.Text(iris.StatusOK, textContents)
}) })
Get("/jsonp", func(ctx *Context) { iris.Get("/jsonp", func(ctx *iris.Context) {
ctx.JSONP(StatusOK, JSONPCallback, JSONPContents) ctx.JSONP(iris.StatusOK, JSONPCallback, JSONPContents)
}) })
Get("/json", func(ctx *Context) { iris.Get("/json", func(ctx *iris.Context) {
ctx.JSON(StatusOK, JSONXMLContents) ctx.JSON(iris.StatusOK, JSONXMLContents)
}) })
Get("/xml", func(ctx *Context) { iris.Get("/xml", func(ctx *iris.Context) {
ctx.XML(StatusOK, JSONXMLContents) ctx.XML(iris.StatusOK, JSONXMLContents)
}) })
Get("/markdown", func(ctx *Context) { iris.Get("/markdown", func(ctx *iris.Context) {
ctx.Markdown(StatusOK, markdownContents) ctx.Markdown(iris.StatusOK, markdownContents)
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
dataT := e.GET("/data").Expect().Status(StatusOK) dataT := e.GET("/data").Expect().Status(iris.StatusOK)
dataT.Header("Content-Type").Equal("application/octet-stream") dataT.Header("Content-Type").Equal("application/octet-stream")
dataT.Body().Equal(string(dataContents)) dataT.Body().Equal(string(dataContents))
textT := e.GET("/text").Expect().Status(StatusOK) textT := e.GET("/text").Expect().Status(iris.StatusOK)
textT.Header("Content-Type").Equal("text/plain; charset=UTF-8") textT.Header("Content-Type").Equal("text/plain; charset=UTF-8")
textT.Body().Equal(textContents) textT.Body().Equal(textContents)
JSONPT := e.GET("/jsonp").Expect().Status(StatusOK) JSONPT := e.GET("/jsonp").Expect().Status(iris.StatusOK)
JSONPT.Header("Content-Type").Equal("application/javascript; charset=UTF-8") JSONPT.Header("Content-Type").Equal("application/javascript; charset=UTF-8")
JSONPT.Body().Equal(JSONPCallback + `({"hello":"jsonp"});`) JSONPT.Body().Equal(JSONPCallback + `({"hello":"jsonp"});`)
JSONT := e.GET("/json").Expect().Status(StatusOK) JSONT := e.GET("/json").Expect().Status(iris.StatusOK)
JSONT.Header("Content-Type").Equal("application/json; charset=UTF-8") JSONT.Header("Content-Type").Equal("application/json; charset=UTF-8")
JSONT.JSON().Object().Equal(JSONXMLContents) JSONT.JSON().Object().Equal(JSONXMLContents)
XMLT := e.GET("/xml").Expect().Status(StatusOK) XMLT := e.GET("/xml").Expect().Status(iris.StatusOK)
XMLT.Header("Content-Type").Equal("text/xml; charset=UTF-8") XMLT.Header("Content-Type").Equal("text/xml; charset=UTF-8")
XMLT.Body().Equal(`<` + JSONXMLContents.XMLName.Local + ` first="` + JSONXMLContents.FirstAttr + `" second="` + JSONXMLContents.SecondAttr + `"><name>` + JSONXMLContents.Name + `</name><birth>` + JSONXMLContents.Birth + `</birth><stars>` + strconv.Itoa(JSONXMLContents.Stars) + `</stars></info>`) XMLT.Body().Equal(`<` + JSONXMLContents.XMLName.Local + ` first="` + JSONXMLContents.FirstAttr + `" second="` + JSONXMLContents.SecondAttr + `"><name>` + JSONXMLContents.Name + `</name><birth>` + JSONXMLContents.Birth + `</birth><stars>` + strconv.Itoa(JSONXMLContents.Stars) + `</stars></info>`)
markdownT := e.GET("/markdown").Expect().Status(StatusOK) markdownT := e.GET("/markdown").Expect().Status(iris.StatusOK)
markdownT.Header("Content-Type").Equal("text/html; charset=UTF-8") markdownT.Header("Content-Type").Equal("text/html; charset=UTF-8")
markdownT.Body().Equal("<h1>" + markdownContents[2:] + "</h1>\n") markdownT.Body().Equal("<h1>" + markdownContents[2:] + "</h1>\n")
} }
func TestContextPreRender(t *testing.T) { func TestContextPreRender(t *testing.T) {
initDefault() iris.ResetDefault()
errMsg1 := "thereIsAnError" errMsg1 := "thereIsAnError"
UsePreRender(func(ctx *Context, src string, binding interface{}, options ...map[string]interface{}) bool { iris.UsePreRender(func(ctx *iris.Context, src string, binding interface{}, options ...map[string]interface{}) bool {
// put the 'Error' binding here, for the shake of the test // put the 'Error' binding here, for the shake of the test
if b, isMap := binding.(map[string]interface{}); isMap { if b, isMap := binding.(map[string]interface{}); isMap {
b["Error"] = errMsg1 b["Error"] = errMsg1
@ -736,7 +740,7 @@ func TestContextPreRender(t *testing.T) {
return true return true
}) })
errMsg2 := "thereIsASecondError" errMsg2 := "thereIsASecondError"
UsePreRender(func(ctx *Context, src string, binding interface{}, options ...map[string]interface{}) bool { iris.UsePreRender(func(ctx *iris.Context, src string, binding interface{}, options ...map[string]interface{}) bool {
// put the 'Error' binding here, for the shake of the test // put the 'Error' binding here, for the shake of the test
if b, isMap := binding.(map[string]interface{}); isMap { if b, isMap := binding.(map[string]interface{}); isMap {
prev := b["Error"].(string) prev := b["Error"].(string)
@ -748,7 +752,7 @@ func TestContextPreRender(t *testing.T) {
}) })
errMsg3 := "thereisAThirdError" errMsg3 := "thereisAThirdError"
UsePreRender(func(ctx *Context, src string, binding interface{}, options ...map[string]interface{}) bool { iris.UsePreRender(func(ctx *iris.Context, src string, binding interface{}, options ...map[string]interface{}) bool {
// put the 'Error' binding here, for the shake of the test // put the 'Error' binding here, for the shake of the test
if b, isMap := binding.(map[string]interface{}); isMap { if b, isMap := binding.(map[string]interface{}); isMap {
prev := b["Error"].(string) prev := b["Error"].(string)
@ -759,11 +763,11 @@ func TestContextPreRender(t *testing.T) {
return true return true
}) })
Get("/", func(ctx *Context) { iris.Get("/", func(ctx *iris.Context) {
ctx.RenderTemplateSource(StatusOK, "<h1>HI {{.Username}}. Error: {{.Error}}</h1>", map[string]interface{}{"Username": "kataras"}) ctx.RenderTemplateSource(iris.StatusOK, "<h1>HI {{.Username}}. Error: {{.Error}}</h1>", map[string]interface{}{"Username": "kataras"})
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
expected := "<h1>HI kataras. Error: " + errMsg1 + errMsg2 + "</h1>" expected := "<h1>HI kataras. Error: " + errMsg1 + errMsg2 + "</h1>"
e.GET("/").Expect().Status(StatusOK).Body().Contains(expected) e.GET("/").Expect().Status(iris.StatusOK).Body().Contains(expected)
} }

View File

@ -1173,7 +1173,7 @@ func (mux *serveMux) BuildHandler() HandlerFunc {
if middleware != nil { if middleware != nil {
// ok we found the correct route, serve it and exit entirely from here // ok we found the correct route, serve it and exit entirely from here
context.Params = params context.Params = params
context.middleware = middleware context.Middleware = middleware
//ctx.Request.Header.SetUserAgentBytes(DefaultUserAgent) //ctx.Request.Header.SetUserAgentBytes(DefaultUserAgent)
context.Do() context.Do()
return return
@ -1420,7 +1420,8 @@ func ParseScheme(domain string) string {
return SchemeHTTP return SchemeHTTP
} }
var proxyHandler = func(proxyAddr string, redirectSchemeAndHost string) fasthttp.RequestHandler { // ProxyHandler returns a new fasthttp handler which works as 'proxy', maybe doesn't suits you look its code before using that in production
var ProxyHandler = func(proxyAddr string, redirectSchemeAndHost string) fasthttp.RequestHandler {
return func(reqCtx *fasthttp.RequestCtx) { return func(reqCtx *fasthttp.RequestCtx) {
// override the handler and redirect all requests to this addr // override the handler and redirect all requests to this addr
redirectTo := redirectSchemeAndHost redirectTo := redirectSchemeAndHost
@ -1458,7 +1459,7 @@ func Proxy(proxyAddr string, redirectSchemeAndHost string) func() error {
proxyAddr = ParseHost(proxyAddr) proxyAddr = ParseHost(proxyAddr)
// override the handler and redirect all requests to this addr // override the handler and redirect all requests to this addr
h := proxyHandler(proxyAddr, redirectSchemeAndHost) h := ProxyHandler(proxyAddr, redirectSchemeAndHost)
prx := New(OptionDisableBanner(true)) prx := New(OptionDisableBanner(true))
prx.Router = h prx.Router = h

View File

@ -1,4 +1,5 @@
package iris // Black-box Testing
package iris_test
/* /*
This is the part we only care, these are end-to-end tests for the mux(router) and the server, the whole http file is made for these reasons only, so these tests are enough I think. This is the part we only care, these are end-to-end tests for the mux(router) and the server, the whole http file is made for these reasons only, so these tests are enough I think.
@ -13,9 +14,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/valyala/fasthttp"
"github.com/gavv/httpexpect" "github.com/gavv/httpexpect"
"github.com/kataras/iris"
"github.com/kataras/iris/httptest"
"github.com/valyala/fasthttp"
) )
const ( const (
@ -75,13 +77,13 @@ func TestParseAddr(t *testing.T) {
// test hosts // test hosts
expectedHost1 := "mydomain.com:1993" expectedHost1 := "mydomain.com:1993"
expectedHost2 := "mydomain.com" expectedHost2 := "mydomain.com"
expectedHost3 := DefaultServerHostname + ":9090" expectedHost3 := iris.DefaultServerHostname + ":9090"
expectedHost4 := "mydomain.com:443" expectedHost4 := "mydomain.com:443"
host1 := ParseHost(expectedHost1) host1 := iris.ParseHost(expectedHost1)
host2 := ParseHost(expectedHost2) host2 := iris.ParseHost(expectedHost2)
host3 := ParseHost(":9090") host3 := iris.ParseHost(":9090")
host4 := ParseHost(expectedHost4) host4 := iris.ParseHost(expectedHost4)
if host1 != expectedHost1 { if host1 != expectedHost1 {
t.Fatalf("Expecting server 1's host to be %s but we got %s", expectedHost1, host1) t.Fatalf("Expecting server 1's host to be %s but we got %s", expectedHost1, host1)
@ -99,13 +101,13 @@ func TestParseAddr(t *testing.T) {
// test hostname // test hostname
expectedHostname1 := "mydomain.com" expectedHostname1 := "mydomain.com"
expectedHostname2 := "mydomain.com" expectedHostname2 := "mydomain.com"
expectedHostname3 := DefaultServerHostname expectedHostname3 := iris.DefaultServerHostname
expectedHostname4 := "mydomain.com" expectedHostname4 := "mydomain.com"
hostname1 := ParseHostname(host1) hostname1 := iris.ParseHostname(host1)
hostname2 := ParseHostname(host2) hostname2 := iris.ParseHostname(host2)
hostname3 := ParseHostname(host3) hostname3 := iris.ParseHostname(host3)
hostname4 := ParseHostname(host4) hostname4 := iris.ParseHostname(host4)
if hostname1 != expectedHostname1 { if hostname1 != expectedHostname1 {
t.Fatalf("Expecting server 1's hostname to be %s but we got %s", expectedHostname1, hostname1) t.Fatalf("Expecting server 1's hostname to be %s but we got %s", expectedHostname1, hostname1)
} }
@ -123,14 +125,14 @@ func TestParseAddr(t *testing.T) {
} }
// test scheme, no need to test fullhost(scheme+host) // test scheme, no need to test fullhost(scheme+host)
expectedScheme1 := SchemeHTTP expectedScheme1 := iris.SchemeHTTP
expectedScheme2 := SchemeHTTP expectedScheme2 := iris.SchemeHTTP
expectedScheme3 := SchemeHTTP expectedScheme3 := iris.SchemeHTTP
expectedScheme4 := SchemeHTTPS expectedScheme4 := iris.SchemeHTTPS
scheme1 := ParseScheme(host1) scheme1 := iris.ParseScheme(host1)
scheme2 := ParseScheme(host2) scheme2 := iris.ParseScheme(host2)
scheme3 := ParseScheme(host3) scheme3 := iris.ParseScheme(host3)
scheme4 := ParseScheme(host4) scheme4 := iris.ParseScheme(host4)
if scheme1 != expectedScheme1 { if scheme1 != expectedScheme1 {
t.Fatalf("Expecting server 1's hostname to be %s but we got %s", expectedScheme1, scheme1) t.Fatalf("Expecting server 1's hostname to be %s but we got %s", expectedScheme1, scheme1)
} }
@ -150,13 +152,13 @@ func TestParseAddr(t *testing.T) {
// Contains the server test for multi running servers // Contains the server test for multi running servers
func TestMultiRunningServers_v1_PROXY(t *testing.T) { func TestMultiRunningServers_v1_PROXY(t *testing.T) {
defer Close() defer iris.Close()
host := "localhost" // you have to add it to your hosts file( for windows, as 127.0.0.1 mydomain.com) host := "localhost" // you have to add it to your hosts file( for windows, as 127.0.0.1 mydomain.com)
hostTLS := "localhost:9999" hostTLS := "localhost:9999"
Close() iris.Close()
defer Close() defer iris.Close()
initDefault() iris.ResetDefault()
Default.Config.DisableBanner = true iris.Default.Config.DisableBanner = true
// create the key and cert files on the fly, and delete them when this test finished // create the key and cert files on the fly, and delete them when this test finished
certFile, ferr := ioutil.TempFile("", "cert") certFile, ferr := ioutil.TempFile("", "cert")
@ -182,34 +184,33 @@ func TestMultiRunningServers_v1_PROXY(t *testing.T) {
certFile.WriteString(testTLSCert) certFile.WriteString(testTLSCert)
keyFile.WriteString(testTLSKey) keyFile.WriteString(testTLSKey)
Get("/", func(ctx *Context) { iris.Get("/", func(ctx *iris.Context) {
ctx.Write("Hello from %s", hostTLS) ctx.Write("Hello from %s", hostTLS)
}) })
go ListenTLS(hostTLS, certFile.Name(), keyFile.Name()) go iris.ListenTLS(hostTLS, certFile.Name(), keyFile.Name())
if ok := <-Default.Available; !ok { if ok := <-iris.Default.Available; !ok {
t.Fatal("Unexpected error: server cannot start, please report this as bug!!") t.Fatal("Unexpected error: server cannot start, please report this as bug!!")
} }
closeProxy := Proxy("localhost:8080", "https://"+hostTLS) closeProxy := iris.Proxy("localhost:8080", "https://"+hostTLS)
defer closeProxy() defer closeProxy()
Default.Config.Tester.ExplicitURL = true e := httptest.New(iris.Default, t, httptest.ExplicitURL(true))
e := Tester(t)
e.Request("GET", "http://"+host+":8080").Expect().Status(StatusOK).Body().Equal("Hello from " + hostTLS) e.Request("GET", "http://"+host+":8080").Expect().Status(iris.StatusOK).Body().Equal("Hello from " + hostTLS)
e.Request("GET", "https://"+hostTLS).Expect().Status(StatusOK).Body().Equal("Hello from " + hostTLS) e.Request("GET", "https://"+hostTLS).Expect().Status(iris.StatusOK).Body().Equal("Hello from " + hostTLS)
} }
// Contains the server test for multi running servers // Contains the server test for multi running servers
func TestMultiRunningServers_v2(t *testing.T) { func TestMultiRunningServers_v2(t *testing.T) {
defer Close() defer iris.Close()
domain := "localhost" domain := "localhost"
hostTLS := "localhost:9999" hostTLS := "localhost:9999"
initDefault() iris.ResetDefault()
Default.Config.DisableBanner = true iris.Default.Config.DisableBanner = true
// create the key and cert files on the fly, and delete them when this test finished // create the key and cert files on the fly, and delete them when this test finished
certFile, ferr := ioutil.TempFile("", "cert") certFile, ferr := ioutil.TempFile("", "cert")
@ -236,7 +237,7 @@ func TestMultiRunningServers_v2(t *testing.T) {
os.Remove(keyFile.Name()) os.Remove(keyFile.Name())
}() }()
Get("/", func(ctx *Context) { iris.Get("/", func(ctx *iris.Context) {
ctx.Write("Hello from %s", hostTLS) ctx.Write("Hello from %s", hostTLS)
}) })
@ -248,24 +249,23 @@ func TestMultiRunningServers_v2(t *testing.T) {
//go Go() //go Go()
// using the proxy handler // using the proxy handler
fsrv1 := &fasthttp.Server{Handler: proxyHandler(domain+":8080", "https://"+hostTLS)} fsrv1 := &fasthttp.Server{Handler: iris.ProxyHandler(domain+":8080", "https://"+hostTLS)}
go fsrv1.ListenAndServe(domain + ":8080") go fsrv1.ListenAndServe(domain + ":8080")
// using the same iris' handler but not as proxy, just the same handler // using the same iris' handler but not as proxy, just the same handler
fsrv2 := &fasthttp.Server{Handler: Default.Router} fsrv2 := &fasthttp.Server{Handler: iris.Default.Router}
go fsrv2.ListenAndServe(domain + ":8888") go fsrv2.ListenAndServe(domain + ":8888")
go ListenTLS(hostTLS, certFile.Name(), keyFile.Name()) go iris.ListenTLS(hostTLS, certFile.Name(), keyFile.Name())
if ok := <-Available; !ok { if ok := <-iris.Default.Available; !ok {
t.Fatal("Unexpected error: server cannot start, please report this as bug!!") t.Fatal("Unexpected error: server cannot start, please report this as bug!!")
} }
Default.Config.Tester.ExplicitURL = true e := httptest.New(iris.Default, t, httptest.ExplicitURL(true))
e := Tester(t)
e.Request("GET", "http://"+domain+":8080").Expect().Status(StatusOK).Body().Equal("Hello from " + hostTLS) e.Request("GET", "http://"+domain+":8080").Expect().Status(iris.StatusOK).Body().Equal("Hello from " + hostTLS)
e.Request("GET", "http://localhost:8888").Expect().Status(StatusOK).Body().Equal("Hello from " + hostTLS) e.Request("GET", "http://localhost:8888").Expect().Status(iris.StatusOK).Body().Equal("Hello from " + hostTLS)
e.Request("GET", "https://"+hostTLS).Expect().Status(StatusOK).Body().Equal("Hello from " + hostTLS) e.Request("GET", "https://"+hostTLS).Expect().Status(iris.StatusOK).Body().Equal("Hello from " + hostTLS)
} }
@ -275,13 +275,13 @@ const (
) )
func testSubdomainHost() string { func testSubdomainHost() string {
s := testSubdomain + "." + Default.Config.VHost s := testSubdomain + "." + iris.Default.Config.VHost
return s return s
} }
func testSubdomainURL() string { func testSubdomainURL() string {
subdomainHost := testSubdomainHost() subdomainHost := testSubdomainHost()
return Default.Config.VScheme + subdomainHost return iris.Default.Config.VScheme + subdomainHost
} }
func subdomainTester(e *httpexpect.Expect) *httpexpect.Expect { func subdomainTester(e *httpexpect.Expect) *httpexpect.Expect {
@ -339,13 +339,13 @@ func TestMuxSimple(t *testing.T) {
{"GET", "/test_get_urlparameter2/second", "/test_get_urlparameter2/second", "name=irisurl&something=anything", "name=irisurl,something=anything", 200, true, nil, []param{{"name", "irisurl"}, {"something", "anything"}}}, {"GET", "/test_get_urlparameter2/second", "/test_get_urlparameter2/second", "name=irisurl&something=anything", "name=irisurl,something=anything", 200, true, nil, []param{{"name", "irisurl"}, {"something", "anything"}}},
{"GET", "/test_get_urlparameter2/first/second/third", "/test_get_urlparameter2/first/second/third", "name=irisurl&something=anything&else=elsehere", "name=irisurl,something=anything,else=elsehere", 200, true, nil, []param{{"name", "irisurl"}, {"something", "anything"}, {"else", "elsehere"}}}, {"GET", "/test_get_urlparameter2/first/second/third", "/test_get_urlparameter2/first/second/third", "name=irisurl&something=anything&else=elsehere", "name=irisurl,something=anything,else=elsehere", 200, true, nil, []param{{"name", "irisurl"}, {"something", "anything"}, {"else", "elsehere"}}},
} }
defer Close() defer iris.Close()
initDefault() iris.ResetDefault()
for idx := range testRoutes { for idx := range testRoutes {
r := testRoutes[idx] r := testRoutes[idx]
if r.Register { if r.Register {
HandleFunc(r.Method, r.Path, func(ctx *Context) { iris.HandleFunc(r.Method, r.Path, func(ctx *iris.Context) {
ctx.SetStatusCode(r.Status) ctx.SetStatusCode(r.Status)
if r.Params != nil && len(r.Params) > 0 { if r.Params != nil && len(r.Params) > 0 {
ctx.SetBodyString(ctx.Params.String()) ctx.SetBodyString(ctx.Params.String())
@ -370,7 +370,7 @@ func TestMuxSimple(t *testing.T) {
} }
} }
e := Tester(t) e := httptest.New(iris.Default, t)
// run the tests (1) // run the tests (1)
for idx := range testRoutes { for idx := range testRoutes {
@ -383,12 +383,12 @@ func TestMuxSimple(t *testing.T) {
} }
func TestMuxSimpleParty(t *testing.T) { func TestMuxSimpleParty(t *testing.T) {
initDefault() iris.ResetDefault()
h := func(c *Context) { c.WriteString(c.HostString() + c.PathString()) } h := func(c *iris.Context) { c.WriteString(c.HostString() + c.PathString()) }
if testEnableSubdomain { if testEnableSubdomain {
subdomainParty := Party(testSubdomain + ".") subdomainParty := iris.Party(testSubdomain + ".")
{ {
subdomainParty.Get("/", h) subdomainParty.Get("/", h)
subdomainParty.Get("/path1", h) subdomainParty.Get("/path1", h)
@ -399,7 +399,7 @@ func TestMuxSimpleParty(t *testing.T) {
} }
// simple // simple
p := Party("/party1") p := iris.Party("/party1")
{ {
p.Get("/", h) p.Get("/", h)
p.Get("/path1", h) p.Get("/path1", h)
@ -408,16 +408,16 @@ func TestMuxSimpleParty(t *testing.T) {
p.Get("/namedpath/:param1/something/:param2/else", h) p.Get("/namedpath/:param1/something/:param2/else", h)
} }
Default.Config.VHost = "0.0.0.0:8080" iris.Default.Config.VHost = "0.0.0.0:8080"
// Default.Config.Tester.Debug = true // iris.Default.Config.Tester.Debug = true
// Default.Config.Tester.ExplicitURL = true // iris.Default.Config.Tester.ExplicitURL = true
e := Tester(t) e := httptest.New(iris.Default, t)
request := func(reqPath string) { request := func(reqPath string) {
e.Request("GET", reqPath). e.Request("GET", reqPath).
Expect(). Expect().
Status(StatusOK).Body().Equal(Default.Config.VHost + reqPath) Status(iris.StatusOK).Body().Equal(iris.Default.Config.VHost + reqPath)
} }
// run the tests // run the tests
@ -432,7 +432,7 @@ func TestMuxSimpleParty(t *testing.T) {
subdomainRequest := func(reqPath string) { subdomainRequest := func(reqPath string) {
es.Request("GET", reqPath). es.Request("GET", reqPath).
Expect(). Expect().
Status(StatusOK).Body().Equal(testSubdomainHost() + reqPath) Status(iris.StatusOK).Body().Equal(testSubdomainHost() + reqPath)
} }
subdomainRequest("/") subdomainRequest("/")
@ -444,33 +444,33 @@ func TestMuxSimpleParty(t *testing.T) {
} }
func TestMuxPathEscape(t *testing.T) { func TestMuxPathEscape(t *testing.T) {
initDefault() iris.ResetDefault()
Get("/details/:name", func(ctx *Context) { iris.Get("/details/:name", func(ctx *iris.Context) {
name := ctx.Param("name") name := ctx.Param("name")
highlight := ctx.URLParam("highlight") highlight := ctx.URLParam("highlight")
ctx.Text(StatusOK, fmt.Sprintf("name=%s,highlight=%s", name, highlight)) ctx.Text(iris.StatusOK, fmt.Sprintf("name=%s,highlight=%s", name, highlight))
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/details/Sakamoto desu ga"). e.GET("/details/Sakamoto desu ga").
WithQuery("highlight", "text"). WithQuery("highlight", "text").
Expect().Status(StatusOK).Body().Equal("name=Sakamoto desu ga,highlight=text") Expect().Status(iris.StatusOK).Body().Equal("name=Sakamoto desu ga,highlight=text")
} }
func TestMuxDecodeURL(t *testing.T) { func TestMuxDecodeURL(t *testing.T) {
initDefault() iris.ResetDefault()
Get("/encoding/:url", func(ctx *Context) { iris.Get("/encoding/:url", func(ctx *iris.Context) {
url := DecodeURL(ctx.Param("url")) url := iris.DecodeURL(ctx.Param("url"))
ctx.SetStatusCode(StatusOK) ctx.SetStatusCode(iris.StatusOK)
ctx.Write(url) ctx.Write(url)
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/encoding/http%3A%2F%2Fsome-url.com").Expect().Status(StatusOK).Body().Equal("http://some-url.com") e.GET("/encoding/http%3A%2F%2Fsome-url.com").Expect().Status(iris.StatusOK).Body().Equal("http://some-url.com")
} }
func TestMuxCustomErrors(t *testing.T) { func TestMuxCustomErrors(t *testing.T) {
@ -500,27 +500,27 @@ func TestMuxCustomErrors(t *testing.T) {
{"TRACE", "/test_trace_panic_custom", "/test_trace_panic_custom", "", internalServerMessage, 500, true, nil, nil}, {"TRACE", "/test_trace_panic_custom", "/test_trace_panic_custom", "", internalServerMessage, 500, true, nil, nil},
} }
) )
initDefault() iris.ResetDefault()
// first register the testRoutes needed // first register the testRoutes needed
for _, r := range testRoutesCustomErrors { for _, r := range testRoutesCustomErrors {
if r.Register { if r.Register {
HandleFunc(r.Method, r.Path, func(ctx *Context) { iris.HandleFunc(r.Method, r.Path, func(ctx *iris.Context) {
ctx.EmitError(r.Status) ctx.EmitError(r.Status)
}) })
} }
} }
// register the custom errors // register the custom errors
OnError(404, func(ctx *Context) { iris.OnError(iris.StatusNotFound, func(ctx *iris.Context) {
ctx.Write("%s", notFoundMessage) ctx.Write("%s", notFoundMessage)
}) })
OnError(500, func(ctx *Context) { iris.OnError(iris.StatusInternalServerError, func(ctx *iris.Context) {
ctx.Write("%s", internalServerMessage) ctx.Write("%s", internalServerMessage)
}) })
// create httpexpect instance that will call fasthtpp.RequestHandler directly // create httpexpect instance that will call fasthtpp.RequestHandler directly
e := Tester(t) e := httptest.New(iris.Default, t)
// run the tests // run the tests
for _, r := range testRoutesCustomErrors { for _, r := range testRoutesCustomErrors {
@ -531,7 +531,7 @@ func TestMuxCustomErrors(t *testing.T) {
} }
type testUserAPI struct { type testUserAPI struct {
*Context *iris.Context
} }
// GET /users // GET /users
@ -560,62 +560,62 @@ func (u testUserAPI) DeleteBy(id string) {
} }
func TestMuxAPI(t *testing.T) { func TestMuxAPI(t *testing.T) {
initDefault() iris.ResetDefault()
middlewareResponseText := "I assume that you are authenticated\n" middlewareResponseText := "I assume that you are authenticated\n"
API("/users", testUserAPI{}, func(ctx *Context) { // optional middleware for .API iris.API("/users", testUserAPI{}, func(ctx *iris.Context) { // optional middleware for .API
// do your work here, or render a login window if not logged in, get the user and send it to the next middleware, or do all here // do your work here, or render a login window if not logged in, get the user and send it to the next middleware, or do all here
ctx.Set("user", "username") ctx.Set("user", "username")
ctx.Next() ctx.Next()
}, func(ctx *Context) { }, func(ctx *iris.Context) {
if ctx.Get("user") == "username" { if ctx.Get("user") == "username" {
ctx.Write(middlewareResponseText) ctx.Write(middlewareResponseText)
ctx.Next() ctx.Next()
} else { } else {
ctx.SetStatusCode(StatusUnauthorized) ctx.SetStatusCode(iris.StatusUnauthorized)
} }
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
userID := "4077" userID := "4077"
formname := "kataras" formname := "kataras"
e.GET("/users").Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Get Users\n") e.GET("/users").Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Get Users\n")
e.GET("/users/" + userID).Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Get By " + userID + "\n") e.GET("/users/" + userID).Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Get By " + userID + "\n")
e.PUT("/users").WithFormField("name", formname).Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Put, name: " + formname + "\n") e.PUT("/users").WithFormField("name", formname).Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Put, name: " + formname + "\n")
e.POST("/users/"+userID).WithFormField("name", formname).Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Post By " + userID + ", name: " + formname + "\n") e.POST("/users/"+userID).WithFormField("name", formname).Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Post By " + userID + ", name: " + formname + "\n")
e.DELETE("/users/" + userID).Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Delete By " + userID + "\n") e.DELETE("/users/" + userID).Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Delete By " + userID + "\n")
} }
func TestMuxAPIWithParty(t *testing.T) { func TestMuxAPIWithParty(t *testing.T) {
initDefault() iris.ResetDefault()
siteParty := Party("sites/:site") siteParty := iris.Party("sites/:site")
middlewareResponseText := "I assume that you are authenticated\n" middlewareResponseText := "I assume that you are authenticated\n"
siteParty.API("/users", testUserAPI{}, func(ctx *Context) { siteParty.API("/users", testUserAPI{}, func(ctx *iris.Context) {
ctx.Set("user", "username") ctx.Set("user", "username")
ctx.Next() ctx.Next()
}, func(ctx *Context) { }, func(ctx *iris.Context) {
if ctx.Get("user") == "username" { if ctx.Get("user") == "username" {
ctx.Write(middlewareResponseText) ctx.Write(middlewareResponseText)
ctx.Next() ctx.Next()
} else { } else {
ctx.SetStatusCode(StatusUnauthorized) ctx.SetStatusCode(iris.StatusUnauthorized)
} }
}) })
e := Tester(t) e := httptest.New(iris.Default, t)
siteID := "1" siteID := "1"
apiPath := "/sites/" + siteID + "/users" apiPath := "/sites/" + siteID + "/users"
userID := "4077" userID := "4077"
formname := "kataras" formname := "kataras"
e.GET(apiPath).Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Get Users\n") e.GET(apiPath).Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Get Users\n")
e.GET(apiPath + "/" + userID).Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Get By " + userID + "\n") e.GET(apiPath + "/" + userID).Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Get By " + userID + "\n")
e.PUT(apiPath).WithFormField("name", formname).Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Put, name: " + formname + "\n") e.PUT(apiPath).WithFormField("name", formname).Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Put, name: " + formname + "\n")
e.POST(apiPath+"/"+userID).WithFormField("name", formname).Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Post By " + userID + ", name: " + formname + "\n") e.POST(apiPath+"/"+userID).WithFormField("name", formname).Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Post By " + userID + ", name: " + formname + "\n")
e.DELETE(apiPath + "/" + userID).Expect().Status(StatusOK).Body().Equal(middlewareResponseText + "Delete By " + userID + "\n") e.DELETE(apiPath + "/" + userID).Expect().Status(iris.StatusOK).Body().Equal(middlewareResponseText + "Delete By " + userID + "\n")
} }
type myTestHandlerData struct { type myTestHandlerData struct {
@ -628,64 +628,64 @@ type myTestCustomHandler struct {
data myTestHandlerData data myTestHandlerData
} }
func (m *myTestCustomHandler) Serve(ctx *Context) { func (m *myTestCustomHandler) Serve(ctx *iris.Context) {
data := &m.data data := &m.data
data.DynamicPathParameter = ctx.Param("myparam") data.DynamicPathParameter = ctx.Param("myparam")
ctx.JSON(StatusOK, data) ctx.JSON(iris.StatusOK, data)
} }
func TestMuxCustomHandler(t *testing.T) { func TestMuxCustomHandler(t *testing.T) {
initDefault() iris.ResetDefault()
myData := myTestHandlerData{ myData := myTestHandlerData{
Sysname: "Redhat", Sysname: "Redhat",
Version: 1, Version: 1,
} }
Handle("GET", "/custom_handler_1/:myparam", &myTestCustomHandler{myData}) iris.Handle("GET", "/custom_handler_1/:myparam", &myTestCustomHandler{myData})
Handle("GET", "/custom_handler_2/:myparam", &myTestCustomHandler{myData}) iris.Handle("GET", "/custom_handler_2/:myparam", &myTestCustomHandler{myData})
e := Tester(t) e := httptest.New(iris.Default, t)
// two times per testRoute // two times per testRoute
param1 := "thisimyparam1" param1 := "thisimyparam1"
expectedData1 := myData expectedData1 := myData
expectedData1.DynamicPathParameter = param1 expectedData1.DynamicPathParameter = param1
e.GET("/custom_handler_1/" + param1).Expect().Status(StatusOK).JSON().Equal(expectedData1) e.GET("/custom_handler_1/" + param1).Expect().Status(iris.StatusOK).JSON().Equal(expectedData1)
param2 := "thisimyparam2" param2 := "thisimyparam2"
expectedData2 := myData expectedData2 := myData
expectedData2.DynamicPathParameter = param2 expectedData2.DynamicPathParameter = param2
e.GET("/custom_handler_1/" + param2).Expect().Status(StatusOK).JSON().Equal(expectedData2) e.GET("/custom_handler_1/" + param2).Expect().Status(iris.StatusOK).JSON().Equal(expectedData2)
param3 := "thisimyparam3" param3 := "thisimyparam3"
expectedData3 := myData expectedData3 := myData
expectedData3.DynamicPathParameter = param3 expectedData3.DynamicPathParameter = param3
e.GET("/custom_handler_2/" + param3).Expect().Status(StatusOK).JSON().Equal(expectedData3) e.GET("/custom_handler_2/" + param3).Expect().Status(iris.StatusOK).JSON().Equal(expectedData3)
param4 := "thisimyparam4" param4 := "thisimyparam4"
expectedData4 := myData expectedData4 := myData
expectedData4.DynamicPathParameter = param4 expectedData4.DynamicPathParameter = param4
e.GET("/custom_handler_2/" + param4).Expect().Status(StatusOK).JSON().Equal(expectedData4) e.GET("/custom_handler_2/" + param4).Expect().Status(iris.StatusOK).JSON().Equal(expectedData4)
} }
func TestMuxFireMethodNotAllowed(t *testing.T) { func TestMuxFireMethodNotAllowed(t *testing.T) {
initDefault() iris.ResetDefault()
Default.Config.FireMethodNotAllowed = true iris.Default.Config.FireMethodNotAllowed = true
h := func(ctx *Context) { h := func(ctx *iris.Context) {
ctx.Write("%s", ctx.MethodString()) ctx.Write("%s", ctx.MethodString())
} }
Default.OnError(StatusMethodNotAllowed, func(ctx *Context) { iris.Default.OnError(iris.StatusMethodNotAllowed, func(ctx *iris.Context) {
ctx.Write("Hello from my custom 405 page") ctx.Write("Hello from my custom 405 page")
}) })
Get("/mypath", h) iris.Get("/mypath", h)
Put("/mypath", h) iris.Put("/mypath", h)
e := Tester(t) e := httptest.New(iris.Default, t)
e.GET("/mypath").Expect().Status(StatusOK).Body().Equal("GET") e.GET("/mypath").Expect().Status(iris.StatusOK).Body().Equal("GET")
e.PUT("/mypath").Expect().Status(StatusOK).Body().Equal("PUT") e.PUT("/mypath").Expect().Status(iris.StatusOK).Body().Equal("PUT")
// this should fail with 405 and catch by the custom http error // this should fail with 405 and catch by the custom http error
e.POST("/mypath").Expect().Status(StatusMethodNotAllowed).Body().Equal("Hello from my custom 405 page") e.POST("/mypath").Expect().Status(iris.StatusMethodNotAllowed).Body().Equal("Hello from my custom 405 page")
Close() iris.Close()
} }

110
httptest/httptest.go Normal file
View File

@ -0,0 +1,110 @@
package httptest
import (
"github.com/gavv/httpexpect"
"github.com/kataras/iris"
"net/http"
"testing"
)
type (
// OptionSetter sets a configuration field to the configuration
OptionSetter interface {
// Set receives a pointer to the Configuration type and does the job of filling it
Set(c *Configuration)
}
// OptionSet implements the OptionSetter
OptionSet func(c *Configuration)
)
// Set is the func which makes the OptionSet an OptionSetter, this is used mostly
func (o OptionSet) Set(c *Configuration) {
o(c)
}
// Configuration httptest configuration
type Configuration struct {
// ExplicitURL If true then the url (should) be prepended manually, useful when want to test subdomains
// Default is false
ExplicitURL bool
// Debug if true then debug messages from the httpexpect will be shown when a test runs
// Default is false
Debug bool
}
// Set implements the OptionSetter for the Configuration itself
func (c Configuration) Set(main *Configuration) {
main.ExplicitURL = c.ExplicitURL
main.Debug = c.Debug
}
var (
// ExplicitURL If true then the url (should) be prepended manually, useful when want to test subdomains
// Default is false
ExplicitURL = func(val bool) OptionSet {
return func(c *Configuration) {
c.ExplicitURL = val
}
}
// Debug if true then debug messages from the httpexpect will be shown when a test runs
// Default is false
Debug = func(val bool) OptionSet {
return func(c *Configuration) {
c.Debug = val
}
}
)
// DefaultConfiguration returns the default configuration for the httptest
// all values are defaulted to false for clarity
func DefaultConfiguration() *Configuration {
return &Configuration{ExplicitURL: false, Debug: false}
}
// New Prepares and returns a new test framework based on the api
// is useful when you need to have more than one test framework for the same iris instance
// usage:
// iris.Get("/mypath", func(ctx *iris.Context){ctx.Write("my body")})
// ...
// e := httptest.New(iris.Default, t)
// e.GET("/mypath").Expect().Status(iris.StatusOK).Body().Equal("my body")
//
// You can find example on the https://github.com/kataras/iris/glob/master/context_test.go
func New(api *iris.Framework, t *testing.T, setters ...OptionSetter) *httpexpect.Expect {
conf := DefaultConfiguration()
for _, setter := range setters {
setter.Set(conf)
}
api.Set(iris.OptionDisableBanner(true))
baseURL := ""
if !api.Plugins.PreBuildFired() {
api.Build()
}
if !conf.ExplicitURL {
baseURL = api.Config.VScheme + api.Config.VHost
// if it's still empty then set it to the default server addr
if baseURL == "" {
baseURL = iris.SchemeHTTP + iris.DefaultServerAddr
}
}
testConfiguration := httpexpect.Config{
BaseURL: baseURL,
Client: &http.Client{
Transport: httpexpect.NewFastBinder(api.Router),
Jar: httpexpect.NewJar(),
},
Reporter: httpexpect.NewAssertReporter(t),
}
if conf.Debug {
testConfiguration.Printers = []httpexpect.Printer{
httpexpect.NewDebugPrinter(t, true),
}
}
return httpexpect.WithConfig(testConfiguration)
}

69
iris.go
View File

@ -54,7 +54,6 @@ import (
"fmt" "fmt"
"log" "log"
"net" "net"
"net/http"
"net/url" "net/url"
"os" "os"
"os/signal" "os/signal"
@ -63,7 +62,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"testing"
"time" "time"
"github.com/gavv/httpexpect" "github.com/gavv/httpexpect"
@ -108,7 +106,16 @@ var (
Available chan bool Available chan bool
) )
func initDefault() { // ResetDefault resets the iris.Default which is the instance which is used on the default iris station for
// iris.Get(all api functions)
// iris.Config
// iris.Logger
// iris.Plugins
// iris.Router
// iris.Websocket
// iris.SSH and iris.Available channel
// useful mostly when you are not using the form of app := iris.New() inside your tests, to make sure that you're using a new iris instance
func ResetDefault() {
Default = New() Default = New()
Config = Default.Config Config = Default.Config
Logger = Default.Logger Logger = Default.Logger
@ -120,7 +127,7 @@ func initDefault() {
} }
func init() { func init() {
initDefault() ResetDefault()
} }
// ------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------
@ -159,7 +166,6 @@ type (
TemplateString(string, interface{}, ...map[string]interface{}) string TemplateString(string, interface{}, ...map[string]interface{}) string
TemplateSourceString(string, interface{}) string TemplateSourceString(string, interface{}) string
SerializeToString(string, interface{}, ...map[string]interface{}) string SerializeToString(string, interface{}, ...map[string]interface{}) string
Tester(*testing.T) *httpexpect.Expect
} }
// Framework is our God |\| Google.Search('Greek mythology Iris') // Framework is our God |\| Google.Search('Greek mythology Iris')
@ -678,7 +684,7 @@ func ReleaseCtx(ctx *Context) {
// see .AcquireCtx & .Serve // see .AcquireCtx & .Serve
func (s *Framework) ReleaseCtx(ctx *Context) { func (s *Framework) ReleaseCtx(ctx *Context) {
ctx.Params = ctx.Params[0:0] ctx.Params = ctx.Params[0:0]
ctx.middleware = nil ctx.Middleware = nil
ctx.session = nil ctx.session = nil
s.contextPool.Put(ctx) s.contextPool.Put(ctx)
} }
@ -1112,55 +1118,6 @@ func (s *Framework) SerializeToString(keyOrContentType string, obj interface{},
return res return res
} }
// NewTester Prepares and returns a new test framework based on the api
// is useful when you need to have more than one test framework for the same iris insttance, otherwise you can use the iris.Tester(t *testing.T)/variable.Tester(t *testing.T)
func NewTester(api *Framework, t *testing.T) *httpexpect.Expect {
api.Set(OptionDisableBanner(true))
baseURL := ""
if api.fsrv == nil {
api.Build()
}
if !api.Config.Tester.ExplicitURL {
baseURL = api.Config.VScheme + api.Config.VHost
// if it's still empty then set it to the default server addr
if baseURL == "" {
baseURL = SchemeHTTP + DefaultServerAddr
}
}
testConfiguration := httpexpect.Config{
BaseURL: baseURL,
Client: &http.Client{
Transport: httpexpect.NewFastBinder(api.Router),
Jar: httpexpect.NewJar(),
},
Reporter: httpexpect.NewAssertReporter(t),
}
if api.Config.Tester.Debug {
testConfiguration.Printers = []httpexpect.Printer{
httpexpect.NewDebugPrinter(t, true),
}
}
return httpexpect.WithConfig(testConfiguration)
}
// Tester returns the test framework for this default insance
func Tester(t *testing.T) *httpexpect.Expect {
return Default.Tester(t)
}
// Tester returns the test framework for this iris insance
func (s *Framework) Tester(t *testing.T) *httpexpect.Expect {
if s.testFramework == nil {
s.testFramework = NewTester(s, t)
}
return s.testFramework
}
// ------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------
// ----------------------------------MuxAPI implementation------------------------------ // ----------------------------------MuxAPI implementation------------------------------
@ -1732,7 +1689,7 @@ func (api *muxAPI) StaticHandler(systemPath string, stripSlashes int, compress b
if errCode == StatusNotFound || errCode == StatusBadRequest || errCode == StatusInternalServerError { if errCode == StatusNotFound || errCode == StatusBadRequest || errCode == StatusInternalServerError {
api.mux.fireError(errCode, ctx) api.mux.fireError(errCode, ctx)
} }
if ctx.pos < uint8(len(ctx.middleware))-1 { if ctx.Pos < uint8(len(ctx.Middleware))-1 {
ctx.Next() // for any case ctx.Next() // for any case
} }

View File

@ -119,23 +119,31 @@ type (
PluginContainer interface { PluginContainer interface {
Add(...Plugin) error Add(...Plugin) error
Remove(string) error Remove(string) error
Len() int
GetName(Plugin) string GetName(Plugin) string
GetDescription(Plugin) string GetDescription(Plugin) string
GetByName(string) Plugin GetByName(string) Plugin
Printf(string, ...interface{}) Printf(string, ...interface{})
Fired(string) int
PreLookup(PreLookupFunc) PreLookup(PreLookupFunc)
DoPreLookup(Route) DoPreLookup(Route)
PreLookupFired() bool
PreBuild(PreBuildFunc) PreBuild(PreBuildFunc)
DoPreBuild(*Framework) DoPreBuild(*Framework)
PreBuildFired() bool
PreListen(PreListenFunc) PreListen(PreListenFunc)
DoPreListen(*Framework) DoPreListen(*Framework)
DoPreListenParallel(*Framework) DoPreListenParallel(*Framework)
PreListenFired() bool
PostListen(PostListenFunc) PostListen(PostListenFunc)
DoPostListen(*Framework) DoPostListen(*Framework)
PostListenFired() bool
PreClose(PreCloseFunc) PreClose(PreCloseFunc)
DoPreClose(*Framework) DoPreClose(*Framework)
PreCloseFired() bool
PreDownload(PreDownloadFunc) PreDownload(PreDownloadFunc)
DoPreDownload(Plugin, string) DoPreDownload(Plugin, string)
PreDownloadFired() bool
// //
GetAll() []Plugin GetAll() []Plugin
// GetDownloader is the only one module that is used and fire listeners at the same time in this file // GetDownloader is the only one module that is used and fire listeners at the same time in this file
@ -248,11 +256,12 @@ type pluginContainer struct {
downloader *pluginDownloadManager downloader *pluginDownloadManager
logger *log.Logger logger *log.Logger
mu sync.Mutex mu sync.Mutex
fired map[string]int // event/plugin type name and the times fired
} }
// newPluginContainer receives a logger and returns a new PluginContainer // newPluginContainer receives a logger and returns a new PluginContainer
func newPluginContainer(l *log.Logger) PluginContainer { func newPluginContainer(l *log.Logger) PluginContainer {
return &pluginContainer{logger: l} return &pluginContainer{logger: l, fired: make(map[string]int, 0)}
} }
// Add activates the plugins and if succeed then adds it to the activated plugins list // Add activates the plugins and if succeed then adds it to the activated plugins list
@ -291,10 +300,6 @@ func (p *pluginContainer) Add(plugins ...Plugin) error {
return nil return nil
} }
func (p *pluginContainer) Reset() {
}
// Remove removes a plugin by it's name, if pluginName is empty "" or no plugin found with this name, then nothing is removed and a specific error is returned. // Remove removes a plugin by it's name, if pluginName is empty "" or no plugin found with this name, then nothing is removed and a specific error is returned.
// This doesn't calls the PreClose method // This doesn't calls the PreClose method
func (p *pluginContainer) Remove(pluginName string) error { func (p *pluginContainer) Remove(pluginName string) error {
@ -322,6 +327,11 @@ func (p *pluginContainer) Remove(pluginName string) error {
return nil return nil
} }
// Len returns the number of activate plugins
func (p *pluginContainer) Len() int {
return len(p.activatedPlugins)
}
// GetName returns the name of a plugin, if no GetName() implemented it returns an empty string "" // GetName returns the name of a plugin, if no GetName() implemented it returns an empty string ""
func (p *pluginContainer) GetName(plugin Plugin) string { func (p *pluginContainer) GetName(plugin Plugin) string {
if pluginObj, ok := plugin.(pluginGetName); ok { if pluginObj, ok := plugin.(pluginGetName); ok {
@ -378,6 +388,29 @@ func (p *pluginContainer) Printf(format string, a ...interface{}) {
} }
// fire adds a fired event on the (statically type named) map and returns the new times
func (p *pluginContainer) fire(name string) int {
p.mu.Lock()
var times int
// maybe unnessecary but for clarity reasons
if t, found := p.fired[name]; found {
times = t
}
times++
p.fired[name] = times
p.mu.Unlock()
return times
}
// Fired receives an event name/plugin type and returns the times which this event is fired and how many plugins are fired this event,
// if zero then it's not fired at all
func (p *pluginContainer) Fired(name string) (times int) {
if t, found := p.fired[name]; found {
times = t
}
return
}
// PreLookup adds a PreLookup plugin-function to the plugin flow container // PreLookup adds a PreLookup plugin-function to the plugin flow container
func (p *pluginContainer) PreLookup(fn PreLookupFunc) { func (p *pluginContainer) PreLookup(fn PreLookupFunc) {
p.Add(fn) p.Add(fn)
@ -388,11 +421,18 @@ func (p *pluginContainer) DoPreLookup(r Route) {
for i := range p.activatedPlugins { for i := range p.activatedPlugins {
// check if this method exists on our plugin obj, these are optionaly and call it // check if this method exists on our plugin obj, these are optionaly and call it
if pluginObj, ok := p.activatedPlugins[i].(pluginPreLookup); ok { if pluginObj, ok := p.activatedPlugins[i].(pluginPreLookup); ok {
// fire will add times to the number of events fired this event
p.fire("prelookup")
pluginObj.PreLookup(r) pluginObj.PreLookup(r)
} }
} }
} }
// PreLookupFired returns true if PreLookup event/ plugin type is fired at least one time
func (p *pluginContainer) PreLookupFired() bool {
return p.Fired("prelookup") > 0
}
// PreBuild adds a PreBuild plugin-function to the plugin flow container // PreBuild adds a PreBuild plugin-function to the plugin flow container
func (p *pluginContainer) PreBuild(fn PreBuildFunc) { func (p *pluginContainer) PreBuild(fn PreBuildFunc) {
p.Add(fn) p.Add(fn)
@ -404,10 +444,16 @@ func (p *pluginContainer) DoPreBuild(station *Framework) {
// check if this method exists on our plugin obj, these are optionaly and call it // check if this method exists on our plugin obj, these are optionaly and call it
if pluginObj, ok := p.activatedPlugins[i].(pluginPreBuild); ok { if pluginObj, ok := p.activatedPlugins[i].(pluginPreBuild); ok {
pluginObj.PreBuild(station) pluginObj.PreBuild(station)
p.fire("prebuild")
} }
} }
} }
// PreBuildFired returns true if PreBuild event/ plugin type is fired at least one time
func (p *pluginContainer) PreBuildFired() bool {
return p.Fired("prebuild") > 0
}
// PreListen adds a PreListen plugin-function to the plugin flow container // PreListen adds a PreListen plugin-function to the plugin flow container
func (p *pluginContainer) PreListen(fn PreListenFunc) { func (p *pluginContainer) PreListen(fn PreListenFunc) {
p.Add(fn) p.Add(fn)
@ -419,6 +465,7 @@ func (p *pluginContainer) DoPreListen(station *Framework) {
// check if this method exists on our plugin obj, these are optionaly and call it // check if this method exists on our plugin obj, these are optionaly and call it
if pluginObj, ok := p.activatedPlugins[i].(pluginPreListen); ok { if pluginObj, ok := p.activatedPlugins[i].(pluginPreListen); ok {
pluginObj.PreListen(station) pluginObj.PreListen(station)
p.fire("prelisten")
} }
} }
} }
@ -433,6 +480,7 @@ func (p *pluginContainer) DoPreListenParallel(station *Framework) {
go func(plugin Plugin) { go func(plugin Plugin) {
if pluginObj, ok := plugin.(pluginPreListen); ok { if pluginObj, ok := plugin.(pluginPreListen); ok {
pluginObj.PreListen(station) pluginObj.PreListen(station)
p.fire("prelisten")
} }
wg.Done() wg.Done()
@ -444,6 +492,11 @@ func (p *pluginContainer) DoPreListenParallel(station *Framework) {
} }
// PreListenFired returns true if PreListen or PreListenParallel event/ plugin type is fired at least one time
func (p *pluginContainer) PreListenFired() bool {
return p.Fired("prelisten") > 0
}
// PostListen adds a PostListen plugin-function to the plugin flow container // PostListen adds a PostListen plugin-function to the plugin flow container
func (p *pluginContainer) PostListen(fn PostListenFunc) { func (p *pluginContainer) PostListen(fn PostListenFunc) {
p.Add(fn) p.Add(fn)
@ -455,10 +508,16 @@ func (p *pluginContainer) DoPostListen(station *Framework) {
// check if this method exists on our plugin obj, these are optionaly and call it // check if this method exists on our plugin obj, these are optionaly and call it
if pluginObj, ok := p.activatedPlugins[i].(pluginPostListen); ok { if pluginObj, ok := p.activatedPlugins[i].(pluginPostListen); ok {
pluginObj.PostListen(station) pluginObj.PostListen(station)
p.fire("postlisten")
} }
} }
} }
// PostListenFired returns true if PostListen event/ plugin type is fired at least one time
func (p *pluginContainer) PostListenFired() bool {
return p.Fired("postlisten") > 0
}
// PreClose adds a PreClose plugin-function to the plugin flow container // PreClose adds a PreClose plugin-function to the plugin flow container
func (p *pluginContainer) PreClose(fn PreCloseFunc) { func (p *pluginContainer) PreClose(fn PreCloseFunc) {
p.Add(fn) p.Add(fn)
@ -470,10 +529,16 @@ func (p *pluginContainer) DoPreClose(station *Framework) {
// check if this method exists on our plugin obj, these are optionaly and call it // check if this method exists on our plugin obj, these are optionaly and call it
if pluginObj, ok := p.activatedPlugins[i].(pluginPreClose); ok { if pluginObj, ok := p.activatedPlugins[i].(pluginPreClose); ok {
pluginObj.PreClose(station) pluginObj.PreClose(station)
p.fire("preclose")
} }
} }
} }
// PreCloseFired returns true if PreCLose event/ plugin type is fired at least one time
func (p *pluginContainer) PreCloseFired() bool {
return p.Fired("preclose") > 0
}
// PreDownload adds a PreDownload plugin-function to the plugin flow container // PreDownload adds a PreDownload plugin-function to the plugin flow container
func (p *pluginContainer) PreDownload(fn PreDownloadFunc) { func (p *pluginContainer) PreDownload(fn PreDownloadFunc) {
p.Add(fn) p.Add(fn)
@ -485,6 +550,12 @@ func (p *pluginContainer) DoPreDownload(pluginTryToDownload Plugin, downloadURL
// check if this method exists on our plugin obj, these are optionaly and call it // check if this method exists on our plugin obj, these are optionaly and call it
if pluginObj, ok := p.activatedPlugins[i].(pluginPreDownload); ok { if pluginObj, ok := p.activatedPlugins[i].(pluginPreDownload); ok {
pluginObj.PreDownload(pluginTryToDownload, downloadURL) pluginObj.PreDownload(pluginTryToDownload, downloadURL)
p.fire("predownload")
} }
} }
} }
// PreDownloadFired returns true if PreDownload event/ plugin type is fired at least one time
func (p *pluginContainer) PreDownloadFired() bool {
return p.Fired("predownload") > 0
}

View File

@ -1,4 +1,5 @@
package iris // Black-box Testing
package iris_test
/* /*
Contains tests for plugin, no end-to-end, just local-object tests, these are enoguh for now. Contains tests for plugin, no end-to-end, just local-object tests, these are enoguh for now.
@ -8,6 +9,7 @@ CONTRIBUTE & DISCUSSION ABOUT TESTS TO: https://github.com/iris-contrib/tests
import ( import (
"fmt" "fmt"
"github.com/kataras/iris"
"testing" "testing"
) )
@ -33,52 +35,52 @@ func (t *testPluginEx) GetDescription() string {
return testPluginExDescription return testPluginExDescription
} }
func (t *testPluginEx) Activate(p PluginContainer) error { func (t *testPluginEx) Activate(p iris.PluginContainer) error {
fmt.Println("Activate Struct") fmt.Println("Activate Struct")
t.activated = true t.activated = true
return nil return nil
} }
func (t *testPluginEx) PreListen(*Framework) { func (t *testPluginEx) PreListen(*iris.Framework) {
fmt.Println("PreListen Struct") fmt.Println("PreListen Struct")
t.prelistenran = true t.prelistenran = true
} }
func (t *testPluginEx) PostListen(*Framework) { func (t *testPluginEx) PostListen(*iris.Framework) {
fmt.Println("PostListen Struct") fmt.Println("PostListen Struct")
t.postlistenran = true t.postlistenran = true
} }
func (t *testPluginEx) PreClose(*Framework) { func (t *testPluginEx) PreClose(*iris.Framework) {
fmt.Println("PreClose Struct") fmt.Println("PreClose Struct")
t.precloseran = true t.precloseran = true
} }
func ExamplePlugins_Add() { func ExamplePlugins_Add() {
initDefault() iris.ResetDefault()
Default.Set(OptionDisableBanner(true)) iris.Default.Set(iris.OptionDisableBanner(true))
Plugins.Add(PreListenFunc(func(*Framework) { iris.Plugins.Add(iris.PreListenFunc(func(*iris.Framework) {
fmt.Println("PreListen Func") fmt.Println("PreListen Func")
})) }))
Plugins.Add(PostListenFunc(func(*Framework) { iris.Plugins.Add(iris.PostListenFunc(func(*iris.Framework) {
fmt.Println("PostListen Func") fmt.Println("PostListen Func")
})) }))
Plugins.Add(PreCloseFunc(func(*Framework) { iris.Plugins.Add(iris.PreCloseFunc(func(*iris.Framework) {
fmt.Println("PreClose Func") fmt.Println("PreClose Func")
})) }))
myplugin := &testPluginEx{} myplugin := &testPluginEx{}
Plugins.Add(myplugin) iris.Plugins.Add(myplugin)
desc := Plugins.GetDescription(myplugin) desc := iris.Plugins.GetDescription(myplugin)
fmt.Println(desc) fmt.Println(desc)
// travis have problems if I do that using // travis have problems if I do that using
// Listen(":8080") and Close() // Listen(":8080") and Close()
Plugins.DoPreListen(Default) iris.Plugins.DoPreListen(iris.Default)
Plugins.DoPostListen(Default) iris.Plugins.DoPostListen(iris.Default)
Plugins.DoPreClose(Default) iris.Plugins.DoPreClose(iris.Default)
// Output: // Output:
// GetName Struct // GetName Struct
@ -95,7 +97,8 @@ func ExamplePlugins_Add() {
// if a plugin has GetName, then it should be registered only one time, the name exists for that reason, it's like unique ID // if a plugin has GetName, then it should be registered only one time, the name exists for that reason, it's like unique ID
func TestPluginDublicateName(t *testing.T) { func TestPluginDublicateName(t *testing.T) {
var plugins pluginContainer iris.ResetDefault()
var plugins = iris.Default.Plugins
firstNamedPlugin := &testPluginEx{} firstNamedPlugin := &testPluginEx{}
sameNamedPlugin := &testPluginEx{} sameNamedPlugin := &testPluginEx{}
// err := plugins.Add(firstNamedPlugin, sameNamedPlugin) or // err := plugins.Add(firstNamedPlugin, sameNamedPlugin) or
@ -107,8 +110,8 @@ func TestPluginDublicateName(t *testing.T) {
if err == nil { if err == nil {
t.Fatalf("Expected an error because of dublicate named plugin!") t.Fatalf("Expected an error because of dublicate named plugin!")
} }
if len(plugins.activatedPlugins) != 1 { if plugins.Len() != 1 {
t.Fatalf("Expected: %d activated plugin but we got: %d", 1, len(plugins.activatedPlugins)) t.Fatalf("Expected: %d activated plugin but we got: %d", 1, plugins.Len())
} }
} }
@ -116,7 +119,7 @@ type testPluginActivationType struct {
shouldError bool shouldError bool
} }
func (t testPluginActivationType) Activate(p PluginContainer) error { func (t testPluginActivationType) Activate(p iris.PluginContainer) error {
p.Add(&testPluginEx{}) p.Add(&testPluginEx{})
if t.shouldError { if t.shouldError {
return fmt.Errorf("An error happens, this plugin and the added plugins by this plugin should not be registered") return fmt.Errorf("An error happens, this plugin and the added plugins by this plugin should not be registered")
@ -125,46 +128,49 @@ func (t testPluginActivationType) Activate(p PluginContainer) error {
} }
func TestPluginActivate(t *testing.T) { func TestPluginActivate(t *testing.T) {
var plugins pluginContainer iris.ResetDefault()
var plugins = iris.Default.Plugins
myplugin := testPluginActivationType{shouldError: false} myplugin := testPluginActivationType{shouldError: false}
plugins.Add(myplugin) plugins.Add(myplugin)
if len(plugins.activatedPlugins) != 2 { // 2 because it registeres a second plugin also if plugins.Len() != 2 { // 2 because it registeres a second plugin also
t.Fatalf("Expected activated plugins to be: %d but we got: %d", 0, len(plugins.activatedPlugins)) t.Fatalf("Expected activated plugins to be: %d but we got: %d", 0, plugins.Len())
} }
} }
// if any error returned from the Activate plugin's method, then this plugin and the plugins it registers should not be registered at all // if any error returned from the Activate plugin's method, then this plugin and the plugins it registers should not be registered at all
func TestPluginActivationError(t *testing.T) { func TestPluginActivationError(t *testing.T) {
var plugins pluginContainer iris.ResetDefault()
var plugins = iris.Default.Plugins
myplugin := testPluginActivationType{shouldError: true} myplugin := testPluginActivationType{shouldError: true}
plugins.Add(myplugin) plugins.Add(myplugin)
if len(plugins.activatedPlugins) > 0 { if plugins.Len() > 0 {
t.Fatalf("Expected activated plugins to be: %d but we got: %d", 0, len(plugins.activatedPlugins)) t.Fatalf("Expected activated plugins to be: %d but we got: %d", 0, plugins.Len())
} }
} }
func TestPluginEvents(t *testing.T) { func TestPluginEvents(t *testing.T) {
var plugins pluginContainer iris.ResetDefault()
var plugins = iris.Default.Plugins
var prelistenran, postlistenran, precloseran bool var prelistenran, postlistenran, precloseran bool
plugins.Add(PreListenFunc(func(*Framework) { plugins.Add(iris.PreListenFunc(func(*iris.Framework) {
prelistenran = true prelistenran = true
})) }))
plugins.Add(PostListenFunc(func(*Framework) { plugins.Add(iris.PostListenFunc(func(*iris.Framework) {
postlistenran = true postlistenran = true
})) }))
plugins.Add(PreCloseFunc(func(*Framework) { plugins.Add(iris.PreCloseFunc(func(*iris.Framework) {
precloseran = true precloseran = true
})) }))
myplugin := &testPluginEx{} myplugin := &testPluginEx{}
plugins.Add(myplugin) plugins.Add(myplugin)
if len(plugins.activatedPlugins) != 4 { if plugins.Len() != 4 {
t.Fatalf("Expected: %d plugins to be registed but we got: %d", 4, len(plugins.activatedPlugins)) t.Fatalf("Expected: %d plugins to be registed but we got: %d", 4, plugins.Len())
} }
desc := plugins.GetDescription(myplugin) desc := plugins.GetDescription(myplugin)
if desc != testPluginExDescription { if desc != testPluginExDescription {