mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
add white box tests for transaction, response writer and some of the context's method
Former-commit-id: 67ea92337f120f03e8bb96d3daa43529b10af2f2
This commit is contained in:
parent
bfeabbd74e
commit
57e5b77853
|
@ -625,26 +625,21 @@ func (mux *serveMux) buildHandler(pool iris.ContextPool) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if mux.hosts && tree.subdomain != "" {
|
if mux.hosts && tree.subdomain != "" {
|
||||||
// context.VirtualHost() is a slow method because it makes
|
|
||||||
// string.Replaces but user can understand that if subdomain then server will have some nano/or/milleseconds performance cost
|
requestHost := context.Host()
|
||||||
requestHost := context.VirtualHostname()
|
|
||||||
hostname := context.Framework().Config.VHost
|
hostname := context.Framework().Config.VHost
|
||||||
|
// println("mux are true and tree.subdomain= " + tree.subdomain + "and hostname = " + hostname + " host = " + requestHost)
|
||||||
if requestHost != hostname {
|
if requestHost != hostname {
|
||||||
//println(requestHost + " != " + mux.hostname)
|
|
||||||
// we have a subdomain
|
// we have a subdomain
|
||||||
if strings.Contains(tree.subdomain, iris.DynamicSubdomainIndicator) {
|
if strings.Contains(tree.subdomain, iris.DynamicSubdomainIndicator) {
|
||||||
} else {
|
} else {
|
||||||
//println(requestHost + " = " + mux.hostname)
|
|
||||||
// mux.host = iris-go.com:8080, the subdomain for example is api.,
|
|
||||||
// so the host must be api.iris-go.com:8080
|
|
||||||
if tree.subdomain+hostname != requestHost {
|
if tree.subdomain+hostname != requestHost {
|
||||||
// go to the next tree, we have a subdomain but it is not the correct
|
// go to the next tree, we have a subdomain but it is not the correct
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//("it's subdomain but the request is the same as the listening addr mux.host == requestHost =>" + mux.host + "=" + requestHost + " ____ and tree's subdomain was: " + tree.subdomain)
|
//("it's subdomain but the request is not the same as the vhost)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
. "gopkg.in/kataras/iris.v6"
|
. "gopkg.in/kataras/iris.v6"
|
||||||
)
|
)
|
||||||
|
|
||||||
// go test -v -run TestConfiguration*
|
// $ go test -v -run TestConfiguration*
|
||||||
|
|
||||||
func TestConfigurationStatic(t *testing.T) {
|
func TestConfigurationStatic(t *testing.T) {
|
||||||
def := DefaultConfiguration()
|
def := DefaultConfiguration()
|
||||||
|
|
|
@ -398,7 +398,8 @@ func (ctx *Context) Subdomain() (subdomain string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// VirtualHostname returns the hostname that user registers, host path maybe differs from the real which is HostString, which taken from a net.listener
|
// VirtualHostname returns the hostname that user registers,
|
||||||
|
// host path maybe differs from the real which is the Host(), which taken from a net.listener
|
||||||
func (ctx *Context) VirtualHostname() string {
|
func (ctx *Context) VirtualHostname() string {
|
||||||
realhost := ctx.Host()
|
realhost := ctx.Host()
|
||||||
hostname := realhost
|
hostname := realhost
|
||||||
|
|
237
context_test.go
Normal file
237
context_test.go
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
package iris_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/kataras/iris.v6"
|
||||||
|
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
|
||||||
|
"gopkg.in/kataras/iris.v6/httptest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// White-box testing *
|
||||||
|
func TestContextDoNextStop(t *testing.T) {
|
||||||
|
var context iris.Context
|
||||||
|
ok := false
|
||||||
|
afterStop := false
|
||||||
|
context.Middleware = iris.Middleware{iris.HandlerFunc(func(*iris.Context) {
|
||||||
|
ok = true
|
||||||
|
}), iris.HandlerFunc(func(*iris.Context) {
|
||||||
|
ok = true
|
||||||
|
}), iris.HandlerFunc(func(*iris.Context) {
|
||||||
|
// this will never execute
|
||||||
|
afterStop = true
|
||||||
|
})}
|
||||||
|
context.Do()
|
||||||
|
if context.Pos != 0 {
|
||||||
|
t.Fatalf("Expecting position 0 for context's middleware but we got: %d", context.Pos)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Unexpected behavior, first context's middleware didn't executed")
|
||||||
|
}
|
||||||
|
ok = false
|
||||||
|
|
||||||
|
context.Next()
|
||||||
|
|
||||||
|
if int(context.Pos) != 1 {
|
||||||
|
t.Fatalf("Expecting to have position %d but we got: %d", 1, context.Pos)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Next context's middleware didn't executed")
|
||||||
|
}
|
||||||
|
|
||||||
|
context.StopExecution()
|
||||||
|
if context.Pos != 255 {
|
||||||
|
t.Fatalf("Context's StopExecution didn't worked, we expected to have position %d but we got %d", 255, context.Pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !context.IsStopped() {
|
||||||
|
t.Fatalf("Should be stopped")
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Next()
|
||||||
|
|
||||||
|
if afterStop {
|
||||||
|
t.Fatalf("We stopped the execution but the next handler was executed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type pathParameter struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
type pathParameters []pathParameter
|
||||||
|
|
||||||
|
// White-box testing *
|
||||||
|
func TestContextParams(t *testing.T) {
|
||||||
|
context := &iris.Context{}
|
||||||
|
params := pathParameters{
|
||||||
|
pathParameter{Key: "testkey", Value: "testvalue"},
|
||||||
|
pathParameter{Key: "testkey2", Value: "testvalue2"},
|
||||||
|
pathParameter{Key: "id", Value: "3"},
|
||||||
|
pathParameter{Key: "bigint", Value: "548921854390354"},
|
||||||
|
}
|
||||||
|
for _, p := range params {
|
||||||
|
context.Set(p.Key, p.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := context.Param(params[0].Key); v != params[0].Value {
|
||||||
|
t.Fatalf("Expecting parameter value to be %s but we got %s", params[0].Value, context.Param("testkey"))
|
||||||
|
}
|
||||||
|
if v := context.Param(params[1].Key); v != params[1].Value {
|
||||||
|
t.Fatalf("Expecting parameter value to be %s but we got %s", params[1].Value, context.Param("testkey2"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if context.ParamsLen() != len(params) {
|
||||||
|
t.Fatalf("Expecting to have %d parameters but we got %d", len(params), context.ParamsLen())
|
||||||
|
}
|
||||||
|
|
||||||
|
if vi, err := context.ParamInt(params[2].Key); err != nil {
|
||||||
|
t.Fatalf("Unexpecting error on context's ParamInt while trying to get the integer of the %s", params[2].Value)
|
||||||
|
} else if vi != 3 {
|
||||||
|
t.Fatalf("Expecting to receive %d but we got %d", 3, vi)
|
||||||
|
}
|
||||||
|
|
||||||
|
if vi, err := context.ParamInt64(params[3].Key); err != nil {
|
||||||
|
t.Fatalf("Unexpecting error on context's ParamInt while trying to get the integer of the %s", params[2].Value)
|
||||||
|
} else if vi != 548921854390354 {
|
||||||
|
t.Fatalf("Expecting to receive %d but we got %d", 548921854390354, vi)
|
||||||
|
}
|
||||||
|
|
||||||
|
// end-to-end test now, note that we will not test the whole mux here, this happens on http_test.go
|
||||||
|
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(httprouter.New())
|
||||||
|
expectedParamsStr := "param1=myparam1,param2=myparam2,param3=myparam3afterstatic,anything=/andhere/anything/you/like"
|
||||||
|
app.Get("/path/:param1/:param2/staticpath/:param3/*anything", func(ctx *iris.Context) {
|
||||||
|
paramsStr := ctx.ParamsSentence()
|
||||||
|
ctx.WriteString(paramsStr)
|
||||||
|
})
|
||||||
|
|
||||||
|
httptest.New(app, t).GET("/path/myparam1/myparam2/staticpath/myparam3afterstatic/andhere/anything/you/like").Expect().Status(iris.StatusOK).Body().Equal(expectedParamsStr)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContextURLParams(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
passedParams := map[string]string{"param1": "value1", "param2": "value2"}
|
||||||
|
app.Get("/", func(ctx *iris.Context) {
|
||||||
|
params := ctx.URLParams()
|
||||||
|
ctx.JSON(iris.StatusOK, params)
|
||||||
|
})
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
e.GET("/").WithQueryObject(passedParams).Expect().Status(iris.StatusOK).JSON().Equal(passedParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hoststring returns the full host, will return the HOST:IP
|
||||||
|
func TestContextHostString(t *testing.T) {
|
||||||
|
app := iris.New(iris.Configuration{VHost: "0.0.0.0:8080"})
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
|
||||||
|
app.Get("/", func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString(ctx.Host())
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/wrong", func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString(ctx.Host() + "w")
|
||||||
|
})
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(app.Config.VHost)
|
||||||
|
e.GET("/wrong").Expect().Body().NotEqual(app.Config.VHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VirtualHostname returns the hostname only,
|
||||||
|
// if the host starts with 127.0.0.1 or localhost it gives the registered hostname part of the listening addr
|
||||||
|
func TestContextVirtualHostName(t *testing.T) {
|
||||||
|
vhost := "mycustomvirtualname.com"
|
||||||
|
app := iris.New(iris.Configuration{VHost: vhost + ":8080"})
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
|
||||||
|
app.Get("/", func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString(ctx.VirtualHostname())
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/wrong", func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString(ctx.VirtualHostname() + "w")
|
||||||
|
})
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(vhost)
|
||||||
|
e.GET("/wrong").Expect().Body().NotEqual(vhost)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContextFormValueString(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(httprouter.New())
|
||||||
|
var k, v string
|
||||||
|
k = "postkey"
|
||||||
|
v = "postvalue"
|
||||||
|
app.Post("/", func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString(k + "=" + ctx.FormValue(k))
|
||||||
|
})
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
e.POST("/").WithFormField(k, v).Expect().Status(iris.StatusOK).Body().Equal(k + "=" + v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContextSubdomain(t *testing.T) {
|
||||||
|
app := iris.New(iris.Configuration{VHost: "mydomain.com:9999"})
|
||||||
|
app.Adapt(httprouter.New())
|
||||||
|
|
||||||
|
//Default.Config.Tester.ListeningAddr = "mydomain.com:9999"
|
||||||
|
// Default.Config.Tester.ExplicitURL = true
|
||||||
|
app.Party("mysubdomain.").Get("/mypath", func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString(ctx.Subdomain())
|
||||||
|
})
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
e.GET("/").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(iris.StatusNotFound)
|
||||||
|
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(iris.StatusNotFound)
|
||||||
|
// e.GET("http://mysubdomain.mydomain.com:9999/mypath").Expect().Status(iris.StatusOK).Body().Equal("mysubdomain")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLimitRequestBodySizeMiddleware(t *testing.T) {
|
||||||
|
const maxBodySize = 1 << 20
|
||||||
|
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
// or inside handler: ctx.SetMaxRequestBodySize(int64(maxBodySize))
|
||||||
|
app.Use(iris.LimitRequestBodySize(maxBodySize))
|
||||||
|
|
||||||
|
app.Post("/", func(ctx *iris.Context) {
|
||||||
|
b, err := ioutil.ReadAll(ctx.Request.Body)
|
||||||
|
if len(b) > maxBodySize {
|
||||||
|
// this is a fatal error it should never happened.
|
||||||
|
t.Fatalf("body is larger (%d) than maxBodySize (%d) even if we add the LimitRequestBodySize middleware", len(b), maxBodySize)
|
||||||
|
}
|
||||||
|
// if is larger then send a bad request status
|
||||||
|
if err != nil {
|
||||||
|
ctx.WriteHeader(iris.StatusBadRequest)
|
||||||
|
ctx.Writef(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Write(b)
|
||||||
|
})
|
||||||
|
|
||||||
|
// UseGlobal should be called at the end used to prepend handlers
|
||||||
|
// app.UseGlobal(iris.LimitRequestBodySize(int64(maxBodySize)))
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
// test with small body
|
||||||
|
e.POST("/").WithBytes([]byte("ok")).Expect().Status(iris.StatusOK).Body().Equal("ok")
|
||||||
|
// test with equal to max body size limit
|
||||||
|
bsent := make([]byte, maxBodySize, maxBodySize)
|
||||||
|
e.POST("/").WithBytes(bsent).Expect().Status(iris.StatusOK).Body().Length().Equal(len(bsent))
|
||||||
|
// test with larger body sent and wait for the custom response
|
||||||
|
largerBSent := make([]byte, maxBodySize+1, maxBodySize+1)
|
||||||
|
e.POST("/").WithBytes(largerBSent).Expect().Status(iris.StatusBadRequest).Body().Equal("http: request body too large")
|
||||||
|
|
||||||
|
}
|
|
@ -62,13 +62,7 @@ func newTestNativeRouter() Policies {
|
||||||
RouterBuilderPolicy: func(repo RouteRepository, context ContextPool) http.Handler {
|
RouterBuilderPolicy: func(repo RouteRepository, context ContextPool) http.Handler {
|
||||||
servemux := http.NewServeMux()
|
servemux := http.NewServeMux()
|
||||||
noIndexRegistered := true
|
noIndexRegistered := true
|
||||||
servemux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if noIndexRegistered {
|
|
||||||
context.Run(w, r, func(ctx *Context) {
|
|
||||||
ctx.EmitError(StatusNotFound)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
repo.Visit(func(route RouteInfo) {
|
repo.Visit(func(route RouteInfo) {
|
||||||
path := route.Path()
|
path := route.Path()
|
||||||
if path == "/" {
|
if path == "/" {
|
||||||
|
@ -86,15 +80,6 @@ func newTestNativeRouter() Policies {
|
||||||
recorder := ctx.Recorder()
|
recorder := ctx.Recorder()
|
||||||
ctx.Do()
|
ctx.Do()
|
||||||
|
|
||||||
// ok, we can't bypass the net/http server.go's err handlers
|
|
||||||
// we have two options:
|
|
||||||
// - create the mux by ourselve, not an ideal because we already done two of them.
|
|
||||||
// - create a new response writer which will check once if user has registered error handler,if yes write that response instead.
|
|
||||||
// - on "/" path(which net/http fallbacks if no any registered route handler found) make if requested_path != "/" or ""
|
|
||||||
// and emit the 404 error, but for the rest of the custom errors...?
|
|
||||||
// - use our custom context's recorder to record the status code, this will be a bit slower solution(maybe not)
|
|
||||||
// but it covers all our scenarios.
|
|
||||||
|
|
||||||
statusCode := recorder.StatusCode()
|
statusCode := recorder.StatusCode()
|
||||||
if statusCode >= 400 { // if we have an error status code try to find a custom error handler
|
if statusCode >= 400 { // if we have an error status code try to find a custom error handler
|
||||||
errorHandler := ctx.Framework().Errors.Get(statusCode)
|
errorHandler := ctx.Framework().Errors.Get(statusCode)
|
||||||
|
@ -113,6 +98,21 @@ func newTestNativeRouter() Policies {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ok, we can't bypass the net/http server.go's err handlers
|
||||||
|
// we have two options:
|
||||||
|
// - create the mux by ourselve, not an ideal because we already done two of them.
|
||||||
|
// - create a new response writer which will check once if user has registered error handler,if yes write that response instead.
|
||||||
|
// - on "/" path(which net/http fallbacks if no any registered route handler found) make if requested_path != "/" or ""
|
||||||
|
// and emit the 404 error, but for the rest of the custom errors...?
|
||||||
|
// - use our custom context's recorder to record the status code, this will be a bit slower solution(maybe not)
|
||||||
|
// but it covers all our scenarios.
|
||||||
|
if noIndexRegistered {
|
||||||
|
servemux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
context.Run(w, r, func(ctx *Context) {
|
||||||
|
ctx.EmitError(StatusNotFound)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
return servemux
|
return servemux
|
||||||
},
|
},
|
||||||
}
|
}
|
163
response_writer_test.go
Normal file
163
response_writer_test.go
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
package iris_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/kataras/iris.v6"
|
||||||
|
"gopkg.in/kataras/iris.v6/httptest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// most tests lives inside context_test.go:Transactions, there lives the response writer's full and coblex tests
|
||||||
|
func TestResponseWriterBeforeFlush(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
|
||||||
|
body := "my body"
|
||||||
|
beforeFlushBody := "body appeneded or setted before callback"
|
||||||
|
|
||||||
|
app.Get("/", func(ctx *iris.Context) {
|
||||||
|
w := ctx.ResponseWriter
|
||||||
|
|
||||||
|
w.SetBeforeFlush(func() {
|
||||||
|
w.WriteString(beforeFlushBody)
|
||||||
|
})
|
||||||
|
|
||||||
|
w.WriteString(body)
|
||||||
|
})
|
||||||
|
|
||||||
|
// recorder can change the status code after write too
|
||||||
|
// it can also be changed everywhere inside the context's lifetime
|
||||||
|
app.Get("/recorder", func(ctx *iris.Context) {
|
||||||
|
w := ctx.Recorder()
|
||||||
|
|
||||||
|
w.SetBeforeFlush(func() {
|
||||||
|
w.SetBodyString(beforeFlushBody)
|
||||||
|
w.WriteHeader(iris.StatusForbidden)
|
||||||
|
})
|
||||||
|
|
||||||
|
w.WriteHeader(iris.StatusOK)
|
||||||
|
w.WriteString(body)
|
||||||
|
})
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(body + beforeFlushBody)
|
||||||
|
e.GET("/recorder").Expect().Status(iris.StatusForbidden).Body().Equal(beforeFlushBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResponseWriterToRecorderMiddleware(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
|
||||||
|
beforeFlushBody := "body appeneded or setted before callback"
|
||||||
|
app.UseGlobal(iris.Recorder)
|
||||||
|
|
||||||
|
app.Get("/", func(ctx *iris.Context) {
|
||||||
|
w := ctx.Recorder()
|
||||||
|
|
||||||
|
w.SetBeforeFlush(func() {
|
||||||
|
w.SetBodyString(beforeFlushBody)
|
||||||
|
w.WriteHeader(iris.StatusForbidden)
|
||||||
|
})
|
||||||
|
|
||||||
|
w.WriteHeader(iris.StatusOK)
|
||||||
|
w.WriteString("this will not be sent at all because of SetBodyString")
|
||||||
|
})
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
e.GET("/").Expect().Status(iris.StatusForbidden).Body().Equal(beforeFlushBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResponseRecorderStatusCodeContentTypeBody(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
|
||||||
|
firstStatusCode := iris.StatusOK
|
||||||
|
contentType := "text/html; charset=" + app.Config.Charset
|
||||||
|
firstBodyPart := "first"
|
||||||
|
secondBodyPart := "second"
|
||||||
|
prependedBody := "zero"
|
||||||
|
expectedBody := prependedBody + firstBodyPart + secondBodyPart
|
||||||
|
|
||||||
|
app.Use(iris.Recorder)
|
||||||
|
// recorder's status code can change if needed by a middleware or the last handler.
|
||||||
|
app.UseFunc(func(ctx *iris.Context) {
|
||||||
|
ctx.SetStatusCode(firstStatusCode)
|
||||||
|
ctx.Next()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.UseFunc(func(ctx *iris.Context) {
|
||||||
|
ctx.SetContentType(contentType)
|
||||||
|
ctx.Next()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.UseFunc(func(ctx *iris.Context) {
|
||||||
|
// set a body ( we will append it later, only with response recorder we can set append or remove a body or a part of it*)
|
||||||
|
ctx.WriteString(firstBodyPart)
|
||||||
|
ctx.Next()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.UseFunc(func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString(secondBodyPart)
|
||||||
|
ctx.Next()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/", func(ctx *iris.Context) {
|
||||||
|
previousStatusCode := ctx.StatusCode()
|
||||||
|
if previousStatusCode != firstStatusCode {
|
||||||
|
t.Fatalf("Previous status code should be %d but got %d", firstStatusCode, previousStatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
previousContentType := ctx.ContentType()
|
||||||
|
if previousContentType != contentType {
|
||||||
|
t.Fatalf("First content type should be %s but got %d", contentType, previousContentType)
|
||||||
|
}
|
||||||
|
// change the status code, this will tested later on (httptest)
|
||||||
|
ctx.SetStatusCode(iris.StatusForbidden)
|
||||||
|
prevBody := string(ctx.Recorder().Body())
|
||||||
|
if prevBody != firstBodyPart+secondBodyPart {
|
||||||
|
t.Fatalf("Previous body (first handler + second handler's writes) expected to be: %s but got: %s", firstBodyPart+secondBodyPart, prevBody)
|
||||||
|
}
|
||||||
|
// test it on httptest later on
|
||||||
|
ctx.Recorder().SetBodyString(prependedBody + prevBody)
|
||||||
|
})
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
et := e.GET("/").Expect().Status(iris.StatusForbidden)
|
||||||
|
et.Header("Content-Type").Equal(contentType)
|
||||||
|
et.Body().Equal(expectedBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleResponseWriter_WriteHeader() {
|
||||||
|
app := iris.New(iris.OptionDisableBanner(true))
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
|
||||||
|
expectedOutput := "Hey"
|
||||||
|
app.Get("/", func(ctx *iris.Context) {
|
||||||
|
|
||||||
|
// here
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
ctx.ResponseWriter.WriteHeader(iris.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Writef(expectedOutput)
|
||||||
|
|
||||||
|
// here
|
||||||
|
fmt.Println(expectedOutput)
|
||||||
|
|
||||||
|
// here
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
ctx.SetStatusCode(iris.StatusOK)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
e := httptest.New(app, nil)
|
||||||
|
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedOutput)
|
||||||
|
// here it shouldn't log an error that status code write multiple times (by the net/http package.)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Hey
|
||||||
|
}
|
122
transaction_test.go
Normal file
122
transaction_test.go
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
package iris_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/kataras/iris.v6"
|
||||||
|
"gopkg.in/kataras/iris.v6/httptest"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTransaction(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
|
||||||
|
firstTransactionFailureMessage := "Error: Virtual failure!!!"
|
||||||
|
secondTransactionSuccessHTMLMessage := "<h1>This will sent at all cases because it lives on different transaction and it doesn't fails</h1>"
|
||||||
|
persistMessage := "<h1>I persist show this message to the client!</h1>"
|
||||||
|
|
||||||
|
maybeFailureTransaction := func(shouldFail bool, isRequestScoped bool) func(t *iris.Transaction) {
|
||||||
|
return func(t *iris.Transaction) {
|
||||||
|
// OPTIONAl, the next transactions and the flow will not be skipped if this transaction fails
|
||||||
|
if isRequestScoped {
|
||||||
|
t.SetScope(iris.RequestTransactionScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OPTIONAL STEP:
|
||||||
|
// create a new custom type of error here to keep track of the status code and reason message
|
||||||
|
err := iris.NewTransactionErrResult()
|
||||||
|
|
||||||
|
t.Context.Text(iris.StatusOK, "Blablabla this should not be sent to the client because we will fill the err with a message and status")
|
||||||
|
|
||||||
|
fail := shouldFail
|
||||||
|
|
||||||
|
if fail {
|
||||||
|
err.StatusCode = iris.StatusInternalServerError
|
||||||
|
err.Reason = firstTransactionFailureMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// OPTIONAl STEP:
|
||||||
|
// but useful if we want to post back an error message to the client if the transaction failed.
|
||||||
|
// if the reason is empty then the transaction completed successfully,
|
||||||
|
// otherwise we rollback the whole response body and cookies and everything lives inside the transaction.Request.
|
||||||
|
t.Complete(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
successTransaction := func(scope *iris.Transaction) {
|
||||||
|
if scope.Context.Request.RequestURI == "/failAllBecauseOfRequestScopeAndFailure" {
|
||||||
|
t.Fatalf("We are inside successTransaction but the previous REQUEST SCOPED TRANSACTION HAS FAILED SO THiS SHOULD NOT BE RAN AT ALL")
|
||||||
|
}
|
||||||
|
scope.Context.HTML(iris.StatusOK,
|
||||||
|
secondTransactionSuccessHTMLMessage)
|
||||||
|
// * if we don't have any 'throw error' logic then no need of scope.Complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
persistMessageHandler := func(ctx *iris.Context) {
|
||||||
|
// OPTIONAL, depends on the usage:
|
||||||
|
// at any case, what ever happens inside the context's transactions send this to the client
|
||||||
|
ctx.HTML(iris.StatusOK, persistMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Get("/failFirsTransactionButSuccessSecondWithPersistMessage", func(ctx *iris.Context) {
|
||||||
|
ctx.BeginTransaction(maybeFailureTransaction(true, false))
|
||||||
|
ctx.BeginTransaction(successTransaction)
|
||||||
|
persistMessageHandler(ctx)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/failFirsTransactionButSuccessSecond", func(ctx *iris.Context) {
|
||||||
|
ctx.BeginTransaction(maybeFailureTransaction(true, false))
|
||||||
|
ctx.BeginTransaction(successTransaction)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/failAllBecauseOfRequestScopeAndFailure", func(ctx *iris.Context) {
|
||||||
|
ctx.BeginTransaction(maybeFailureTransaction(true, true))
|
||||||
|
ctx.BeginTransaction(successTransaction)
|
||||||
|
})
|
||||||
|
|
||||||
|
customErrorTemplateText := "<h1>custom error</h1>"
|
||||||
|
app.OnError(iris.StatusInternalServerError, func(ctx *iris.Context) {
|
||||||
|
ctx.Text(iris.StatusInternalServerError, customErrorTemplateText)
|
||||||
|
})
|
||||||
|
|
||||||
|
failureWithRegisteredErrorHandler := func(ctx *iris.Context) {
|
||||||
|
ctx.BeginTransaction(func(transaction *iris.Transaction) {
|
||||||
|
transaction.SetScope(iris.RequestTransactionScope)
|
||||||
|
err := iris.NewTransactionErrResult()
|
||||||
|
err.StatusCode = iris.StatusInternalServerError // set only the status code in order to execute the registered template
|
||||||
|
transaction.Complete(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.Text(iris.StatusOK, "this will not be sent to the client because first is requested scope and it's failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Get("/failAllBecauseFirstTransactionFailedWithRegisteredErrorTemplate", failureWithRegisteredErrorHandler)
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
e.GET("/failFirsTransactionButSuccessSecondWithPersistMessage").
|
||||||
|
Expect().
|
||||||
|
Status(iris.StatusOK).
|
||||||
|
ContentType("text/html", app.Config.Charset).
|
||||||
|
Body().
|
||||||
|
Equal(secondTransactionSuccessHTMLMessage + persistMessage)
|
||||||
|
|
||||||
|
e.GET("/failFirsTransactionButSuccessSecond").
|
||||||
|
Expect().
|
||||||
|
Status(iris.StatusOK).
|
||||||
|
ContentType("text/html", app.Config.Charset).
|
||||||
|
Body().
|
||||||
|
Equal(secondTransactionSuccessHTMLMessage)
|
||||||
|
|
||||||
|
e.GET("/failAllBecauseOfRequestScopeAndFailure").
|
||||||
|
Expect().
|
||||||
|
Status(iris.StatusInternalServerError).
|
||||||
|
Body().
|
||||||
|
Equal(firstTransactionFailureMessage)
|
||||||
|
|
||||||
|
e.GET("/failAllBecauseFirstTransactionFailedWithRegisteredErrorTemplate").
|
||||||
|
Expect().
|
||||||
|
Status(iris.StatusInternalServerError).
|
||||||
|
Body().
|
||||||
|
Equal(customErrorTemplateText)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user