mirror of
https://github.com/kataras/iris.git
synced 2026-01-25 12:55:57 +00:00
add the stale release
This commit is contained in:
@@ -10,11 +10,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/core/errgroup"
|
||||
"github.com/kataras/iris/v12/hero"
|
||||
"github.com/kataras/iris/v12/macro"
|
||||
macroHandler "github.com/kataras/iris/v12/macro/handler"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/errgroup"
|
||||
"github.com/kataras/iris/hero"
|
||||
"github.com/kataras/iris/macro"
|
||||
macroHandler "github.com/kataras/iris/macro/handler"
|
||||
)
|
||||
|
||||
// MethodNone is a Virtual method
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
)
|
||||
|
||||
//
|
||||
// randStringBytesMaskImprSrc helps us to generate random paths for the test,
|
||||
// the below piece of code is external, as an answer to a stackoverflow question.
|
||||
//
|
||||
// START.
|
||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const (
|
||||
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||
)
|
||||
|
||||
var src = rand.NewSource(time.Now().UnixNano())
|
||||
|
||||
func randStringBytesMaskImprSrc(n int) string {
|
||||
b := make([]byte, n)
|
||||
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
||||
if remain == 0 {
|
||||
cache, remain = src.Int63(), letterIdxMax
|
||||
}
|
||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||
b[i] = letterBytes[idx]
|
||||
i--
|
||||
}
|
||||
cache >>= letterIdxBits
|
||||
remain--
|
||||
}
|
||||
|
||||
return strings.ToLower(string(b))
|
||||
}
|
||||
|
||||
// END.
|
||||
|
||||
func genPaths(routesLength, minCharLength, maxCharLength int) []string {
|
||||
// b := new(strings.Builder)
|
||||
b := new(bytes.Buffer)
|
||||
paths := make([]string, routesLength)
|
||||
pathStart := '/'
|
||||
for i := 0; i < routesLength; i++ {
|
||||
pathSegmentCharsLength := rand.Intn(maxCharLength-minCharLength) + minCharLength
|
||||
|
||||
b.WriteRune(pathStart)
|
||||
b.WriteString(randStringBytesMaskImprSrc(pathSegmentCharsLength))
|
||||
b.WriteString("/{name:string}/") // sugar.
|
||||
b.WriteString(randStringBytesMaskImprSrc(pathSegmentCharsLength))
|
||||
b.WriteString("/{age:int}/end")
|
||||
paths[i] = b.String()
|
||||
|
||||
b.Reset()
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
// Build 1296(=144*9(the available http methods)) routes
|
||||
// with up to 2*range(15-42)+ 2 named paths lowercase letters
|
||||
// and 12 request handlers each.
|
||||
//
|
||||
// GOCACHE=off && go test -run=XXX -bench=BenchmarkAPIBuilder$ -benchtime=10s
|
||||
func BenchmarkAPIBuilder(b *testing.B) {
|
||||
rand.Seed(time.Now().Unix())
|
||||
|
||||
noOpHandler := func(ctx *context.Context) {}
|
||||
handlersPerRoute := make(context.Handlers, 12)
|
||||
for i := 0; i < cap(handlersPerRoute); i++ {
|
||||
handlersPerRoute[i] = noOpHandler
|
||||
}
|
||||
|
||||
routesLength := 144
|
||||
// i.e /gzhyweumidvelqewrvoyqmzopvuxli/{name:string}/bibrkratnrrhvsjwsxygfwmqwhcstc/{age:int}/end
|
||||
paths := genPaths(routesLength, 15, 42)
|
||||
|
||||
api := NewAPIBuilder()
|
||||
requestHandler := NewDefaultHandler(nil, nil)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < routesLength; i++ {
|
||||
api.Any(paths[i], handlersPerRoute...)
|
||||
}
|
||||
|
||||
if err := requestHandler.Build(api); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
|
||||
b.Logf("%d routes have just builded\n", len(api.GetRoutes()))
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package router
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/hero"
|
||||
"github.com/kataras/iris/v12/macro"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/hero"
|
||||
"github.com/kataras/iris/macro"
|
||||
)
|
||||
|
||||
// APIContainer is a wrapper of a common `Party` featured by Dependency Injection.
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/context"
|
||||
)
|
||||
|
||||
const indexName = "/index.html"
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/core/errgroup"
|
||||
"github.com/kataras/iris/v12/core/netutil"
|
||||
macroHandler "github.com/kataras/iris/v12/macro/handler"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/errgroup"
|
||||
"github.com/kataras/iris/core/netutil"
|
||||
macroHandler "github.com/kataras/iris/macro/handler"
|
||||
|
||||
"github.com/kataras/golog"
|
||||
"github.com/kataras/pio"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/context"
|
||||
)
|
||||
|
||||
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
package router_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
var (
|
||||
finalExecutionRulesResponse = "1234"
|
||||
|
||||
testExecutionResponse = func(t *testing.T, app *iris.Application, path string) {
|
||||
e := httptest.New(t, app)
|
||||
e.GET(path).Expect().Status(httptest.StatusOK).Body().Equal(finalExecutionRulesResponse)
|
||||
}
|
||||
)
|
||||
|
||||
func writeStringHandler(text string, withNext bool) context.Handler {
|
||||
return func(ctx *context.Context) {
|
||||
ctx.WriteString(text)
|
||||
if withNext {
|
||||
ctx.Next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterExecutionRulesForceMain(t *testing.T) {
|
||||
app := iris.New()
|
||||
begin := app.Party("/")
|
||||
begin.SetExecutionRules(router.ExecutionRules{Main: router.ExecutionOptions{Force: true}})
|
||||
|
||||
// no need of `ctx.Next()` all main handlers should be executed with the Main.Force:True rule.
|
||||
begin.Get("/", writeStringHandler("12", false), writeStringHandler("3", false), writeStringHandler("4", false))
|
||||
|
||||
testExecutionResponse(t, app, "/")
|
||||
}
|
||||
|
||||
func TestRouterExecutionRulesForceBegin(t *testing.T) {
|
||||
app := iris.New()
|
||||
begin := app.Party("/begin_force")
|
||||
begin.SetExecutionRules(router.ExecutionRules{Begin: router.ExecutionOptions{Force: true}})
|
||||
|
||||
// should execute, begin rule is to force execute them without `ctx.Next()`.
|
||||
begin.Use(writeStringHandler("1", false))
|
||||
begin.Use(writeStringHandler("2", false))
|
||||
// begin starts with begin and ends to the main handlers but not last, so this done should not be executed.
|
||||
begin.Done(writeStringHandler("5", false))
|
||||
begin.Get("/", writeStringHandler("3", false), writeStringHandler("4", false))
|
||||
|
||||
testExecutionResponse(t, app, "/begin_force")
|
||||
}
|
||||
|
||||
func TestRouterExecutionRulesForceDone(t *testing.T) {
|
||||
app := iris.New()
|
||||
done := app.Party("/done_force")
|
||||
done.SetExecutionRules(router.ExecutionRules{Done: router.ExecutionOptions{Force: true}})
|
||||
|
||||
// these done should be executed without `ctx.Next()`
|
||||
done.Done(writeStringHandler("3", false), writeStringHandler("4", false))
|
||||
// first with `ctx.Next()`, because Done.Force:True rule will alter the latest of the main handler(s) only.
|
||||
done.Get("/", writeStringHandler("1", true), writeStringHandler("2", false))
|
||||
|
||||
// rules should be kept in children.
|
||||
doneChild := done.Party("/child")
|
||||
// even if only one, it's the latest, Done.Force:True rule should modify it.
|
||||
doneChild.Get("/", writeStringHandler("12", false))
|
||||
|
||||
testExecutionResponse(t, app, "/done_force")
|
||||
testExecutionResponse(t, app, "/done_force/child")
|
||||
}
|
||||
|
||||
func TestRouterExecutionRulesShouldNotModifyTheCallersHandlerAndChildrenCanResetExecutionRules(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.SetExecutionRules(router.ExecutionRules{Done: router.ExecutionOptions{Force: true}})
|
||||
h := writeStringHandler("4", false)
|
||||
|
||||
app.Done(h)
|
||||
app.Get("/", writeStringHandler("123", false))
|
||||
|
||||
// remember: the handler stored in var didn't had a `ctx.Next()`, modified its clone above with adding a `ctx.Next()`
|
||||
// note the "clone" word, the original handler shouldn't be changed.
|
||||
app.Party("/c").SetExecutionRules(router.ExecutionRules{}).Get("/", h, writeStringHandler("err caller modified!", false))
|
||||
|
||||
testExecutionResponse(t, app, "/")
|
||||
|
||||
e := httptest.New(t, app)
|
||||
e.GET("/c").Expect().Status(httptest.StatusOK).Body().Equal("4") // the "should not" should not be written.
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"mime"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/context"
|
||||
)
|
||||
|
||||
var types = map[string]string{
|
||||
|
||||
@@ -3,9 +3,9 @@ package router
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/core/errgroup"
|
||||
"github.com/kataras/iris/v12/macro"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/errgroup"
|
||||
"github.com/kataras/iris/macro"
|
||||
)
|
||||
|
||||
// Party is just a group joiner of routes which have the same prefix and share same middleware(s) also.
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/kataras/iris/v12/core/netutil"
|
||||
"github.com/kataras/iris/v12/macro"
|
||||
"github.com/kataras/iris/v12/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/v12/macro/interpreter/lexer"
|
||||
"github.com/kataras/iris/core/netutil"
|
||||
"github.com/kataras/iris/macro"
|
||||
"github.com/kataras/iris/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/macro/interpreter/lexer"
|
||||
)
|
||||
|
||||
// Param receives a parameter name prefixed with the ParamStart symbol.
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCleanPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
"/",
|
||||
"/",
|
||||
},
|
||||
{
|
||||
"noslashPrefix",
|
||||
"/noslashPrefix",
|
||||
},
|
||||
{
|
||||
"slashSuffix/",
|
||||
"/slashSuffix",
|
||||
},
|
||||
{
|
||||
"noSlashPrefixAndslashSuffix/",
|
||||
"/noSlashPrefixAndslashSuffix",
|
||||
},
|
||||
// don't do any clean up inside {},
|
||||
// fixes #927.
|
||||
{
|
||||
"/total/{year:string regexp(\\d{4})}",
|
||||
"/total/{year:string regexp(\\d{4})}",
|
||||
},
|
||||
{
|
||||
"/total/{year:string regexp(\\d{4})}/more",
|
||||
"/total/{year:string regexp(\\d{4})}/more",
|
||||
},
|
||||
{
|
||||
"/total/{year:string regexp(\\d{4})}/more/{s:string regexp(\\d{7})}",
|
||||
"/total/{year:string regexp(\\d{4})}/more/{s:string regexp(\\d{7})}",
|
||||
},
|
||||
{
|
||||
"/single_no_params",
|
||||
"/single_no_params",
|
||||
},
|
||||
{
|
||||
"/single/{id:uint64}",
|
||||
"/single/{id:uint64}",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
if expected, got := tt.expected, cleanPath(tt.path); expected != got {
|
||||
t.Fatalf("[%d] - expected path '%s' but got '%s'", i, expected, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
"/v2/stores/{id:string format(uuid)} /v3",
|
||||
[]string{"/v2/stores/{id:string format(uuid)}", "/v3"},
|
||||
},
|
||||
{
|
||||
"/user/{id:uint64} /admin/{id:uint64}",
|
||||
[]string{"/user/{id:uint64}", "/admin/{id:uint64}"},
|
||||
},
|
||||
{
|
||||
"/users/{id:int} /admins/{id:int64}",
|
||||
[]string{"/users/{id:int}", "/admins/{id:int64}"},
|
||||
},
|
||||
{
|
||||
"/user /admin",
|
||||
[]string{"/user", "/admin"},
|
||||
},
|
||||
{
|
||||
"/single_no_params",
|
||||
[]string{"/single_no_params"},
|
||||
},
|
||||
{
|
||||
"/single/{id:int}",
|
||||
[]string{"/single/{id:int}"},
|
||||
},
|
||||
}
|
||||
|
||||
equalSlice := func(s1 []string, s2 []string) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range s1 {
|
||||
if s2[i] != s1[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
paths := splitPath(tt.path)
|
||||
if expected, got := tt.expected, paths; !equalSlice(expected, got) {
|
||||
t.Fatalf("[%d] - expected paths '%#v' but got '%#v'", i, expected, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitSubdomainAndPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
original string
|
||||
subdomain string
|
||||
path string
|
||||
}{
|
||||
{"admin./users/42", "admin.", "/users/42"},
|
||||
{"static.", "static.", "/"},
|
||||
{"static./" + WildcardFileParam(), "static.", "/" + WildcardFileParam()},
|
||||
{"//api/users\\42", "", "/api/users/42"},
|
||||
{"admin./users//42", "admin.", "/users/42"},
|
||||
{"*./users/42/", "*.", "/users/42"},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
subdomain, path := splitSubdomainAndPath(tt.original)
|
||||
|
||||
if expected, got := tt.subdomain, subdomain; expected != got {
|
||||
t.Fatalf("[%d] - expected subdomain '%s' but got '%s'", i, expected, got)
|
||||
}
|
||||
if expected, got := tt.path, path; expected != got {
|
||||
t.Fatalf("[%d] - expected path '%s' but got '%s'", i, expected, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/macro"
|
||||
"github.com/kataras/iris/v12/macro/handler"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/macro"
|
||||
"github.com/kataras/iris/macro/handler"
|
||||
|
||||
"github.com/kataras/pio"
|
||||
)
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
package router_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
func TestRegisterRule(t *testing.T) {
|
||||
app := iris.New()
|
||||
v1 := app.Party("/v1")
|
||||
v1.SetRegisterRule(iris.RouteSkip)
|
||||
|
||||
getHandler := func(ctx iris.Context) {
|
||||
ctx.Writef("[get] %s", ctx.Method())
|
||||
}
|
||||
|
||||
anyHandler := func(ctx iris.Context) {
|
||||
ctx.Writef("[any] %s", ctx.Method())
|
||||
}
|
||||
|
||||
getRoute := v1.Get("/", getHandler)
|
||||
v1.Any("/", anyHandler)
|
||||
if route := v1.Get("/", getHandler); !reflect.DeepEqual(route, getRoute) {
|
||||
t.Fatalf("expected route to be equal with the original get route")
|
||||
}
|
||||
|
||||
// test RouteSkip.
|
||||
e := httptest.New(t, app, httptest.LogLevel("error"))
|
||||
testRegisterRule(e, "[get] GET")
|
||||
|
||||
// test RouteOverride (default behavior).
|
||||
v1.SetRegisterRule(iris.RouteOverride)
|
||||
v1.Any("/", anyHandler)
|
||||
app.RefreshRouter()
|
||||
testRegisterRule(e, "[any] GET")
|
||||
|
||||
// test RouteError.
|
||||
v1.SetRegisterRule(iris.RouteError)
|
||||
if route := v1.Get("/", getHandler); route != nil {
|
||||
t.Fatalf("expected duplicated route, with RouteError rule, to be nil but got: %#+v", route)
|
||||
}
|
||||
if expected, got := 1, len(v1.GetReporter().Errors); expected != got {
|
||||
t.Fatalf("expected api builder's errors length to be: %d but got: %d", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func testRegisterRule(e *httptest.Expect, expectedGetBody string) {
|
||||
for _, method := range router.AllMethods {
|
||||
tt := e.Request(method, "/v1").Expect().Status(httptest.StatusOK).Body()
|
||||
if method == iris.MethodGet {
|
||||
tt.Equal(expectedGetBody)
|
||||
} else {
|
||||
tt.Equal("[any] " + method)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterRuleOverlap(t *testing.T) {
|
||||
app := iris.New()
|
||||
// TODO(@kataras) the overlapping does not work per-party yet,
|
||||
// it just checks compares from the total app's routes (which is the best possible action to do
|
||||
// because MVC applications can be separated into different parties too?).
|
||||
usersRouter := app.Party("/users")
|
||||
usersRouter.SetRegisterRule(iris.RouteOverlap)
|
||||
|
||||
// second handler will be executed, status will be reset-ed as well,
|
||||
// stop without data written.
|
||||
usersRouter.Get("/", func(ctx iris.Context) {
|
||||
ctx.StopWithStatus(iris.StatusUnauthorized)
|
||||
})
|
||||
usersRouter.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString("data")
|
||||
})
|
||||
|
||||
// first handler will be executed, no stop called.
|
||||
usersRouter.Get("/p1", func(ctx iris.Context) {
|
||||
ctx.StatusCode(iris.StatusUnauthorized)
|
||||
})
|
||||
usersRouter.Get("/p1", func(ctx iris.Context) {
|
||||
ctx.WriteString("not written")
|
||||
})
|
||||
|
||||
// first handler will be executed, stop but with data sent on default writer
|
||||
// (body sent cannot be reset-ed here).
|
||||
usersRouter.Get("/p2", func(ctx iris.Context) {
|
||||
ctx.StopWithText(iris.StatusUnauthorized, "no access")
|
||||
})
|
||||
usersRouter.Get("/p2", func(ctx iris.Context) {
|
||||
ctx.WriteString("not written")
|
||||
})
|
||||
|
||||
// second will be executed, response can be reset-ed on recording.
|
||||
usersRouter.Get("/p3", func(ctx iris.Context) {
|
||||
ctx.Record()
|
||||
ctx.StopWithText(iris.StatusUnauthorized, "no access")
|
||||
})
|
||||
usersRouter.Get("/p3", func(ctx iris.Context) {
|
||||
ctx.WriteString("p3 data")
|
||||
})
|
||||
|
||||
e := httptest.New(t, app)
|
||||
|
||||
e.GET("/users").Expect().Status(httptest.StatusOK).Body().Equal("data")
|
||||
e.GET("/users/p1").Expect().Status(httptest.StatusUnauthorized).Body().Equal("Unauthorized")
|
||||
e.GET("/users/p2").Expect().Status(httptest.StatusUnauthorized).Body().Equal("no access")
|
||||
e.GET("/users/p3").Expect().Status(httptest.StatusOK).Body().Equal("p3 data")
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// white-box testing
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12/macro"
|
||||
)
|
||||
|
||||
func TestRouteStaticPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
tmpl string
|
||||
static string
|
||||
}{
|
||||
{
|
||||
tmpl: "/files/{file:path}",
|
||||
static: "/files",
|
||||
},
|
||||
{
|
||||
tmpl: "/path",
|
||||
static: "/path",
|
||||
},
|
||||
{
|
||||
tmpl: "/path/segment",
|
||||
static: "/path/segment",
|
||||
},
|
||||
{
|
||||
tmpl: "/path/segment/{n:int}",
|
||||
static: "/path/segment",
|
||||
},
|
||||
{
|
||||
tmpl: "/path/{n:uint64}/{n:int}",
|
||||
static: "/path",
|
||||
},
|
||||
{
|
||||
tmpl: "/path/{n:uint64}/static",
|
||||
static: "/path",
|
||||
},
|
||||
{
|
||||
tmpl: "/{name}",
|
||||
static: "/",
|
||||
},
|
||||
{
|
||||
tmpl: "/",
|
||||
static: "/",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
route := Route{tmpl: macro.Template{Src: tt.tmpl}}
|
||||
if expected, got := tt.static, route.StaticPath(); expected != got {
|
||||
t.Fatalf("[%d:%s] expected static path to be: '%s' but got: '%s'", i, tt.tmpl, expected, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/context"
|
||||
|
||||
"github.com/schollz/closestmatch"
|
||||
)
|
||||
|
||||
@@ -1,287 +0,0 @@
|
||||
// black-box testing
|
||||
//
|
||||
// see _examples/routing/main_test.go for the most common router tests that you may want to see,
|
||||
// this is a test which makes sure that the APIBuilder's `UseGlobal`, `Use` and `Done` functions are
|
||||
// working as expected.
|
||||
|
||||
package router_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
// test registering of below handlers
|
||||
// with a different order but the route's final
|
||||
// response should be the same at all cases.
|
||||
var (
|
||||
writeHandler = func(s string) iris.Handler {
|
||||
return func(ctx iris.Context) {
|
||||
ctx.WriteString(s)
|
||||
ctx.Next()
|
||||
}
|
||||
}
|
||||
|
||||
mainResponse = "main"
|
||||
mainHandler = writeHandler(mainResponse)
|
||||
|
||||
firstUseResponse = "use1"
|
||||
firstUseHandler = writeHandler(firstUseResponse)
|
||||
|
||||
secondUseResponse = "use2"
|
||||
secondUseHandler = writeHandler(secondUseResponse)
|
||||
|
||||
firstUseRouterResponse = "userouter1"
|
||||
// Use inline handler, no the `writeHandler`,
|
||||
// because it will be overriden by `secondUseRouterHandler` otherwise,
|
||||
// look `UseRouter:context.UpsertHandlers` for more.
|
||||
firstUseRouterHandler = func(ctx iris.Context) {
|
||||
ctx.WriteString(firstUseRouterResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
secondUseRouterResponse = "userouter2"
|
||||
secondUseRouterHandler = writeHandler(secondUseRouterResponse)
|
||||
|
||||
firstUseGlobalResponse = "useglobal1"
|
||||
firstUseGlobalHandler = writeHandler(firstUseGlobalResponse)
|
||||
|
||||
secondUseGlobalResponse = "useglobal2"
|
||||
secondUseGlobalHandler = writeHandler(secondUseGlobalResponse)
|
||||
|
||||
firstDoneResponse = "done1"
|
||||
firstDoneHandler = writeHandler(firstDoneResponse)
|
||||
|
||||
secondDoneResponse = "done2"
|
||||
secondDoneHandler = func(ctx iris.Context) {
|
||||
ctx.WriteString(secondDoneResponse)
|
||||
}
|
||||
|
||||
finalResponse = firstUseRouterResponse + secondUseRouterResponse + firstUseGlobalResponse + secondUseGlobalResponse +
|
||||
firstUseResponse + secondUseResponse + mainResponse + firstDoneResponse + secondDoneResponse
|
||||
|
||||
testResponse = func(t *testing.T, app *iris.Application, path string) {
|
||||
t.Helper()
|
||||
|
||||
e := httptest.New(t, app)
|
||||
e.GET(path).Expect().Status(httptest.StatusOK).Body().Equal(finalResponse)
|
||||
}
|
||||
)
|
||||
|
||||
func TestMiddlewareByRouteDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler)
|
||||
app.UseRouter(secondUseRouterHandler)
|
||||
|
||||
app.Get("/mypath", firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler,
|
||||
mainHandler, firstDoneHandler, secondDoneHandler)
|
||||
|
||||
testResponse(t, app, "/mypath")
|
||||
}
|
||||
|
||||
func TestMiddlewareByUseAndDoneDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||
app.Use(firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler)
|
||||
app.Done(firstDoneHandler, secondDoneHandler)
|
||||
|
||||
app.Get("/mypath", mainHandler)
|
||||
|
||||
testResponse(t, app, "/mypath")
|
||||
}
|
||||
|
||||
func TestMiddlewareByUseUseGlobalAndDoneDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
|
||||
app.Use(firstUseHandler, secondUseHandler)
|
||||
// if failed then UseGlobal didnt' registered these handlers even before the
|
||||
// existing middleware.
|
||||
app.UseGlobal(firstUseGlobalHandler, secondUseGlobalHandler)
|
||||
app.Done(firstDoneHandler, secondDoneHandler)
|
||||
|
||||
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||
app.Get("/mypath", mainHandler)
|
||||
|
||||
testResponse(t, app, "/mypath")
|
||||
}
|
||||
|
||||
func TestMiddlewareByUseDoneAndUseGlobalDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||
|
||||
app.Use(firstUseHandler, secondUseHandler)
|
||||
app.Done(firstDoneHandler, secondDoneHandler)
|
||||
|
||||
app.Get("/mypath", mainHandler)
|
||||
|
||||
// if failed then UseGlobal was unable to
|
||||
// prepend these handlers to the route was registered before
|
||||
// OR
|
||||
// when order failed because these should be executed in order, first the firstUseGlobalHandler,
|
||||
// because they are the same type (global begin handlers)
|
||||
app.UseGlobal(firstUseGlobalHandler)
|
||||
app.UseGlobal(secondUseGlobalHandler)
|
||||
|
||||
testResponse(t, app, "/mypath")
|
||||
}
|
||||
|
||||
func TestMiddlewareByUseGlobalUseAndDoneGlobalDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler)
|
||||
app.UseRouter(secondUseRouterHandler)
|
||||
|
||||
app.UseGlobal(firstUseGlobalHandler)
|
||||
app.UseGlobal(secondUseGlobalHandler)
|
||||
app.Use(firstUseHandler, secondUseHandler)
|
||||
|
||||
app.Get("/mypath", mainHandler)
|
||||
|
||||
app.DoneGlobal(firstDoneHandler, secondDoneHandler)
|
||||
|
||||
testResponse(t, app, "/mypath")
|
||||
}
|
||||
|
||||
func TestMiddlewareByDoneUseAndUseGlobalDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||
app.Done(firstDoneHandler, secondDoneHandler)
|
||||
|
||||
app.Use(firstUseHandler, secondUseHandler)
|
||||
|
||||
app.Get("/mypath", mainHandler)
|
||||
|
||||
app.UseGlobal(firstUseGlobalHandler)
|
||||
app.UseGlobal(secondUseGlobalHandler)
|
||||
|
||||
testResponse(t, app, "/mypath")
|
||||
}
|
||||
|
||||
func TestUseRouterStopExecution(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(func(ctx iris.Context) {
|
||||
ctx.WriteString("stop")
|
||||
// no ctx.Next, so the router has not even the chance to work.
|
||||
})
|
||||
app.Get("/", writeHandler("index"))
|
||||
|
||||
e := httptest.New(t, app)
|
||||
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal("stop")
|
||||
|
||||
app = iris.New()
|
||||
app.OnErrorCode(iris.StatusForbidden, func(ctx iris.Context) {
|
||||
ctx.Writef("err: %v", ctx.GetErr())
|
||||
})
|
||||
app.UseRouter(func(ctx iris.Context) {
|
||||
ctx.StopWithPlainError(iris.StatusForbidden, fmt.Errorf("custom error"))
|
||||
// stopped but not data written yet, the error code handler
|
||||
// should be responsible of it (use StopWithError to write and close).
|
||||
})
|
||||
app.Get("/", writeHandler("index"))
|
||||
|
||||
e = httptest.New(t, app)
|
||||
e.GET("/").Expect().Status(iris.StatusForbidden).Body().Equal("err: custom error")
|
||||
}
|
||||
|
||||
func TestUseRouterParentDisallow(t *testing.T) {
|
||||
const expectedResponse = "no_userouter_allowed"
|
||||
|
||||
app := iris.New()
|
||||
app.UseRouter(func(ctx iris.Context) {
|
||||
ctx.WriteString("always")
|
||||
ctx.Next()
|
||||
})
|
||||
app.Get("/index", func(ctx iris.Context) {
|
||||
ctx.WriteString(expectedResponse)
|
||||
})
|
||||
|
||||
app.SetPartyMatcher(func(p iris.Party, ctx iris.Context) bool {
|
||||
// modifies the PartyMatcher to not match any UseRouter,
|
||||
// tests should receive the handlers response alone.
|
||||
return false
|
||||
})
|
||||
|
||||
app.PartyFunc("/", func(p iris.Party) { // it's the same instance of app.
|
||||
p.UseRouter(func(ctx iris.Context) {
|
||||
ctx.WriteString("_2")
|
||||
ctx.Next()
|
||||
})
|
||||
p.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString(expectedResponse)
|
||||
})
|
||||
})
|
||||
|
||||
app.PartyFunc("/user", func(p iris.Party) {
|
||||
p.UseRouter(func(ctx iris.Context) {
|
||||
ctx.WriteString("_3")
|
||||
ctx.Next()
|
||||
})
|
||||
|
||||
p.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString(expectedResponse)
|
||||
})
|
||||
})
|
||||
|
||||
e := httptest.New(t, app)
|
||||
e.GET("/index").Expect().Status(iris.StatusOK).Body().Equal(expectedResponse)
|
||||
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedResponse)
|
||||
e.GET("/user").Expect().Status(iris.StatusOK).Body().Equal(expectedResponse)
|
||||
}
|
||||
|
||||
func TestUseRouterSubdomains(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(func(ctx iris.Context) {
|
||||
if ctx.Subdomain() == "old" {
|
||||
ctx.Next() // call the router, do not write.
|
||||
return
|
||||
}
|
||||
|
||||
// if we write here, it will always give 200 OK,
|
||||
// even on not registered routes, that's the point at the end,
|
||||
// full control here when we need it.
|
||||
ctx.WriteString("always_")
|
||||
ctx.Next()
|
||||
})
|
||||
|
||||
adminAPI := app.Subdomain("admin")
|
||||
adminAPI.UseRouter(func(ctx iris.Context) {
|
||||
ctx.WriteString("admin always_")
|
||||
ctx.Next()
|
||||
})
|
||||
adminAPI.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString("admin")
|
||||
})
|
||||
|
||||
adminControlAPI := adminAPI.Subdomain("control")
|
||||
adminControlAPI.UseRouter(func(ctx iris.Context) {
|
||||
ctx.WriteString("control admin always_")
|
||||
ctx.Next()
|
||||
})
|
||||
adminControlAPI.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString("control admin")
|
||||
})
|
||||
|
||||
oldAPI := app.Subdomain("old")
|
||||
oldAPI.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString("chat")
|
||||
})
|
||||
|
||||
e := httptest.New(t, app, httptest.URL("http://example.com"))
|
||||
e.GET("/notfound").Expect().Status(iris.StatusOK).Body().Equal("always_")
|
||||
|
||||
e.GET("/").WithURL("http://admin.example.com").Expect().Status(iris.StatusOK).Body().
|
||||
Equal("always_admin always_admin")
|
||||
|
||||
e.GET("/").WithURL("http://control.admin.example.com").Expect().Status(iris.StatusOK).Body().
|
||||
Equal("always_admin always_control admin always_control admin")
|
||||
|
||||
// It has a route, and use router just proceeds to the router.
|
||||
e.GET("/").WithURL("http://old.example.com").Expect().Status(iris.StatusOK).Body().
|
||||
Equal("chat")
|
||||
// this is not a registered path, should fire 404, the UseRouter does not write
|
||||
// anything to the response writer, so the router has control over it.
|
||||
e.GET("/notfound").WithURL("http://old.example.com").Expect().Status(iris.StatusNotFound).Body().
|
||||
Equal("Not Found")
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/core/netutil"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/netutil"
|
||||
)
|
||||
|
||||
type subdomainRedirectWrapper struct {
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package router_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
func TestRouteExists(t *testing.T) {
|
||||
// build the api
|
||||
app := iris.New()
|
||||
emptyHandler := func(*context.Context) {}
|
||||
|
||||
// setup the tested routes
|
||||
app.Handle("GET", "/route-exists", emptyHandler)
|
||||
app.Handle("POST", "/route-with-param/{param}", emptyHandler)
|
||||
|
||||
// check RouteExists
|
||||
app.Handle("GET", "/route-test", func(ctx *context.Context) {
|
||||
if ctx.RouteExists("GET", "/route-not-exists") {
|
||||
t.Error("Route with path should not exists")
|
||||
}
|
||||
|
||||
if ctx.RouteExists("POST", "/route-exists") {
|
||||
t.Error("Route with method should not exists")
|
||||
}
|
||||
|
||||
if !ctx.RouteExists("GET", "/route-exists") {
|
||||
t.Error("Route 1 should exists")
|
||||
}
|
||||
|
||||
if !ctx.RouteExists("POST", "/route-with-param/a-param") {
|
||||
t.Error("Route 2 should exists")
|
||||
}
|
||||
})
|
||||
|
||||
// run the tests
|
||||
httptest.New(t, app, httptest.Debug(false)).Request("GET", "/route-test").Expect().Status(iris.StatusOK)
|
||||
}
|
||||
|
||||
func TestLowercaseRouting(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.WrapRouter(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
// test bottom to begin wrapper, the last ones should execute first.
|
||||
// The ones that are registered at `Build` state, after this `WrapRouter` call.
|
||||
// So path should be already lowecased.
|
||||
if expected, got := strings.ToLower(r.URL.Path), r.URL.Path; expected != got {
|
||||
t.Fatalf("expected path: %s but got: %s", expected, got)
|
||||
}
|
||||
next(w, r)
|
||||
})
|
||||
|
||||
h := func(ctx iris.Context) { ctx.WriteString(ctx.Path()) }
|
||||
|
||||
// Register routes.
|
||||
tests := []string{"/", "/lowercase", "/UPPERCASE", "/Title", "/m1xEd2"}
|
||||
for _, tt := range tests {
|
||||
app.Get(tt, h)
|
||||
}
|
||||
|
||||
app.Configure(iris.WithLowercaseRouting)
|
||||
// Test routes.
|
||||
e := httptest.New(t, app)
|
||||
for _, tt := range tests {
|
||||
s := strings.ToLower(tt)
|
||||
e.GET(tt).Expect().Status(httptest.StatusOK).Body().Equal(s)
|
||||
e.GET(s).Expect().Status(httptest.StatusOK).Body().Equal(s)
|
||||
e.GET(strings.ToUpper(tt)).Expect().Status(httptest.StatusOK).Body().Equal(s)
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
// black-box testing
|
||||
//
|
||||
// see _examples/routing/main_test.go for the most common router tests that you may want to see,
|
||||
// this is a test for the new feature that I just coded: wildcard "/{p:path}" on root without conflicts
|
||||
|
||||
package router_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
const (
|
||||
same_as_request_path = "same"
|
||||
from_status_code = "from"
|
||||
staticPathPrefixBody = "from the static path: "
|
||||
prefix_static_path_following_by_request_path = "prefix_same"
|
||||
)
|
||||
|
||||
type testRouteRequest struct {
|
||||
method string
|
||||
subdomain string
|
||||
path string
|
||||
expectedStatusCode int
|
||||
expectedBody string
|
||||
}
|
||||
|
||||
type testRoute struct {
|
||||
method string
|
||||
path string
|
||||
handler context.Handler
|
||||
requests []testRouteRequest
|
||||
}
|
||||
|
||||
var h = func(ctx *context.Context) {
|
||||
ctx.WriteString(ctx.Path())
|
||||
}
|
||||
|
||||
var h2 = func(ctx *context.Context) {
|
||||
ctx.StatusCode(iris.StatusForbidden) // ! 200 but send the body as expected,
|
||||
// we need that kind of behavior to determinate which handler is executed for routes that
|
||||
// both having wildcard path but first one is registered on root level.
|
||||
ctx.WriteString(ctx.Path())
|
||||
}
|
||||
|
||||
func h3(ctx *context.Context) {
|
||||
ctx.Writef(staticPathPrefixBody + ctx.Path())
|
||||
}
|
||||
|
||||
func TestRouterWildcardDifferentPrefixPath(t *testing.T) {
|
||||
tt := []testRoute{
|
||||
{"GET", "/s/{p:path}", h, []testRouteRequest{
|
||||
{"GET", "", "/s/that/is/wildcard", iris.StatusOK, same_as_request_path},
|
||||
{"GET", "", "/s/ok", iris.StatusOK, same_as_request_path},
|
||||
}},
|
||||
{"GET", "/som/{p:path}", h, []testRouteRequest{
|
||||
{"GET", "", "/som/that/is/wildcard", iris.StatusOK, same_as_request_path},
|
||||
{"GET", "", "/som/ok", iris.StatusOK, same_as_request_path},
|
||||
}},
|
||||
{"GET", "/some/{p:path}", h, []testRouteRequest{
|
||||
{"GET", "", "/some/that/is/wildcard", iris.StatusOK, same_as_request_path},
|
||||
{"GET", "", "/some1/that/is/wildcard", iris.StatusNotFound, from_status_code},
|
||||
}},
|
||||
}
|
||||
|
||||
testTheRoutes(t, tt, false)
|
||||
}
|
||||
|
||||
func TestRouterWildcardAndStatic(t *testing.T) {
|
||||
tt := []testRoute{
|
||||
{"GET", "/some/{p:path}", h2, []testRouteRequest{
|
||||
{"GET", "", "/some/that/is/wildcard", iris.StatusForbidden, same_as_request_path},
|
||||
{"GET", "", "/some/did", iris.StatusForbidden, same_as_request_path},
|
||||
{"GET", "", "/some1/that/is/wildcard", iris.StatusNotFound, from_status_code},
|
||||
}},
|
||||
{"GET", "/some/static", h, []testRouteRequest{
|
||||
{"GET", "", "/some/static", iris.StatusOK, same_as_request_path},
|
||||
}},
|
||||
|
||||
{"GET", "/s/{p:path}", h2, []testRouteRequest{
|
||||
{"GET", "", "/s/that/is/wildcard", iris.StatusForbidden, same_as_request_path},
|
||||
{"GET", "", "/s/did", iris.StatusForbidden, same_as_request_path},
|
||||
{"GET", "", "/s1/that/is/wildcard", iris.StatusNotFound, from_status_code},
|
||||
}},
|
||||
{"GET", "/s/static", h, []testRouteRequest{
|
||||
{"GET", "", "/s/static", iris.StatusOK, same_as_request_path},
|
||||
}},
|
||||
}
|
||||
|
||||
testTheRoutes(t, tt, false)
|
||||
}
|
||||
|
||||
func TestRouterWildcardRootMany(t *testing.T) {
|
||||
tt := []testRoute{
|
||||
// all routes will be handlded by "h" because we added wildcard to root,
|
||||
// this feature is very important and can remove noumerous of previous hacks on our apps.
|
||||
{"GET", "/{p:path}", h, []testRouteRequest{
|
||||
{"GET", "", "/this/is/wildcard/on/root", iris.StatusOK, same_as_request_path},
|
||||
}}, // mormally, order matters, root should be registered at last
|
||||
// but we change the front level order algorithm to put last these automatically
|
||||
// see handler.go
|
||||
{"GET", "/some/{p:path}", h2, []testRouteRequest{
|
||||
{"GET", "", "/some/that/is/wildcard", iris.StatusForbidden, same_as_request_path},
|
||||
{"GET", "", "/some/did", iris.StatusForbidden, same_as_request_path},
|
||||
}},
|
||||
{"GET", "/some/static", h, []testRouteRequest{
|
||||
{"GET", "", "/some/static", iris.StatusOK, same_as_request_path},
|
||||
}},
|
||||
{"GET", "/some1", h, []testRouteRequest{
|
||||
{"GET", "", "/some1", iris.StatusOK, same_as_request_path},
|
||||
// this will show up because of the first wildcard, as we wanted to do.
|
||||
{"GET", "", "/some1/that/is/wildcard", iris.StatusOK, same_as_request_path},
|
||||
}},
|
||||
}
|
||||
|
||||
testTheRoutes(t, tt, false)
|
||||
}
|
||||
|
||||
func TestRouterWildcardRootManyAndRootStatic(t *testing.T) {
|
||||
tt := []testRoute{
|
||||
// routes that may return 404 will be handled by the below route ("h" handler) because we added wildcard to root,
|
||||
// this feature is very important and can remove noumerous of previous hacks on our apps.
|
||||
//
|
||||
// Static paths and parameters have priority over wildcard, all three types can be registered in the same path prefix.
|
||||
//
|
||||
// Remember, all of those routes are registered don't be tricked by the visual appearance of the below test blocks.
|
||||
{"GET", "/{p:path}", h, []testRouteRequest{
|
||||
{"GET", "", "/other2almost/some", iris.StatusOK, same_as_request_path},
|
||||
}},
|
||||
{"GET", "/static/{p:path}", h, []testRouteRequest{
|
||||
{"GET", "", "/static", iris.StatusOK, same_as_request_path}, // HERE<- IF NOT FOUND THEN BACKWARDS TO WILDCARD IF THERE IS ONE, HMM.
|
||||
{"GET", "", "/static/something/here", iris.StatusOK, same_as_request_path},
|
||||
}},
|
||||
{"GET", "/", h, []testRouteRequest{
|
||||
{"GET", "", "/", iris.StatusOK, same_as_request_path},
|
||||
}},
|
||||
{"GET", "/other/{paramother:path}", h2, []testRouteRequest{
|
||||
// OK and not h2 because of the root wildcard.
|
||||
{"GET", "", "/other", iris.StatusOK, same_as_request_path},
|
||||
{"GET", "", "/other/wildcard", iris.StatusForbidden, same_as_request_path},
|
||||
{"GET", "", "/other/wildcard/here", iris.StatusForbidden, same_as_request_path},
|
||||
}},
|
||||
{"GET", "/other2/{paramothersecond:path}", h2, []testRouteRequest{
|
||||
{"GET", "", "/other2/wildcard", iris.StatusForbidden, same_as_request_path},
|
||||
{"GET", "", "/other2/more/than/one/path/parts", iris.StatusForbidden, same_as_request_path},
|
||||
}},
|
||||
{"GET", "/other2/static", h3, []testRouteRequest{
|
||||
{"GET", "", "/other2/static", iris.StatusOK, prefix_static_path_following_by_request_path},
|
||||
// h2(Forbiddenn) instead of h3 OK because it will be handled by the /other2/{paramothersecond:path}'s handler which gives 403.
|
||||
{"GET", "", "/other2/staticed", iris.StatusForbidden, same_as_request_path},
|
||||
}},
|
||||
}
|
||||
|
||||
testTheRoutes(t, tt, false)
|
||||
}
|
||||
|
||||
func testTheRoutes(t *testing.T, tests []testRoute, debug bool) {
|
||||
// build the api
|
||||
app := iris.New()
|
||||
for _, tt := range tests {
|
||||
app.Handle(tt.method, tt.path, tt.handler)
|
||||
}
|
||||
|
||||
// setup the test suite
|
||||
e := httptest.New(t, app, httptest.Debug(debug))
|
||||
|
||||
// run the tests
|
||||
for _, tt := range tests {
|
||||
for _, req := range tt.requests {
|
||||
// t.Logf("req: %s:%s\n", tt.method, tt.path)
|
||||
method := req.method
|
||||
if method == "" {
|
||||
method = tt.method
|
||||
}
|
||||
ex := e.Request(method, req.path)
|
||||
if req.subdomain != "" {
|
||||
ex.WithURL("http://" + req.subdomain + ".localhost:8080")
|
||||
}
|
||||
|
||||
expectedBody := req.expectedBody
|
||||
if req.expectedBody == same_as_request_path {
|
||||
expectedBody = req.path
|
||||
}
|
||||
if req.expectedBody == from_status_code {
|
||||
expectedBody = http.StatusText(req.expectedStatusCode)
|
||||
}
|
||||
if req.expectedBody == prefix_static_path_following_by_request_path {
|
||||
expectedBody = staticPathPrefixBody + req.path
|
||||
}
|
||||
|
||||
ex.Expect().Status(req.expectedStatusCode).Body().Equal(expectedBody)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMakeWrapperFunc(t *testing.T) {
|
||||
var (
|
||||
firstBody = []byte("1")
|
||||
secondBody = []byte("2")
|
||||
mainBody = []byte("3")
|
||||
expectedBody = append(firstBody, append(secondBody, mainBody...)...)
|
||||
)
|
||||
|
||||
pre := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
w.Header().Set("X-Custom", "data")
|
||||
next(w, r)
|
||||
}
|
||||
|
||||
first := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
w.Write(firstBody)
|
||||
next(w, r)
|
||||
}
|
||||
|
||||
second := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
w.Write(secondBody)
|
||||
next(w, r)
|
||||
}
|
||||
|
||||
mainHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(mainBody)
|
||||
}
|
||||
|
||||
wrapper := makeWrapperFunc(second, first)
|
||||
wrapper = makeWrapperFunc(wrapper, pre)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "https://iris-go.com", nil)
|
||||
wrapper(w, r, mainHandler)
|
||||
|
||||
if got := w.Body.Bytes(); !bytes.Equal(expectedBody, got) {
|
||||
t.Fatalf("expected boy: %s but got: %s", string(expectedBody), string(got))
|
||||
}
|
||||
|
||||
if expected, got := "data", w.Header().Get("X-Custom"); expected != got {
|
||||
t.Fatalf("expected x-custom header: %s but got: %s", expected, got)
|
||||
}
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
// black-box testing
|
||||
package router_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/context"
|
||||
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
var defaultErrHandler = func(ctx *context.Context) {
|
||||
text := http.StatusText(ctx.GetStatusCode())
|
||||
ctx.WriteString(text)
|
||||
}
|
||||
|
||||
func TestOnAnyErrorCode(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.Configure(iris.WithFireMethodNotAllowed)
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
expectedPrintBeforeExecuteErr := "printed before error"
|
||||
|
||||
// with a middleware
|
||||
app.OnAnyErrorCode(func(ctx *context.Context) {
|
||||
buff.WriteString(expectedPrintBeforeExecuteErr)
|
||||
ctx.Next()
|
||||
}, defaultErrHandler)
|
||||
|
||||
expectedFoundResponse := "found"
|
||||
app.Get("/found", func(ctx *context.Context) {
|
||||
ctx.WriteString(expectedFoundResponse)
|
||||
})
|
||||
|
||||
expected407 := "this should be sent, we manage the response response by ourselves"
|
||||
app.Get("/407", func(ctx *context.Context) {
|
||||
ctx.Record()
|
||||
ctx.WriteString(expected407)
|
||||
ctx.StatusCode(iris.StatusProxyAuthRequired)
|
||||
})
|
||||
|
||||
e := httptest.New(t, app)
|
||||
|
||||
e.GET("/found").Expect().Status(iris.StatusOK).
|
||||
Body().Equal(expectedFoundResponse)
|
||||
|
||||
e.GET("/notfound").Expect().Status(iris.StatusNotFound).
|
||||
Body().Equal(http.StatusText(iris.StatusNotFound))
|
||||
|
||||
checkAndClearBuf(t, buff, expectedPrintBeforeExecuteErr)
|
||||
|
||||
e.POST("/found").Expect().Status(iris.StatusMethodNotAllowed).
|
||||
Body().Equal(http.StatusText(iris.StatusMethodNotAllowed))
|
||||
|
||||
checkAndClearBuf(t, buff, expectedPrintBeforeExecuteErr)
|
||||
|
||||
e.GET("/407").Expect().Status(iris.StatusProxyAuthRequired).
|
||||
Body().Equal(expected407)
|
||||
|
||||
// Test Configuration.ResetOnFireErrorCode.
|
||||
app2 := iris.New()
|
||||
app2.Configure(iris.WithResetOnFireErrorCode)
|
||||
|
||||
app2.OnAnyErrorCode(func(ctx *context.Context) {
|
||||
buff.WriteString(expectedPrintBeforeExecuteErr)
|
||||
ctx.Next()
|
||||
}, defaultErrHandler)
|
||||
|
||||
app2.Get("/406", func(ctx *context.Context) {
|
||||
ctx.Record()
|
||||
ctx.WriteString("this should not be sent, only status text will be sent")
|
||||
ctx.WriteString("the handler can handle 'rollback' of the text when error code fired because of the recorder")
|
||||
ctx.StatusCode(iris.StatusNotAcceptable)
|
||||
})
|
||||
|
||||
httptest.New(t, app2).GET("/406").Expect().Status(iris.StatusNotAcceptable).
|
||||
Body().Equal(http.StatusText(iris.StatusNotAcceptable))
|
||||
|
||||
checkAndClearBuf(t, buff, expectedPrintBeforeExecuteErr)
|
||||
}
|
||||
|
||||
func checkAndClearBuf(t *testing.T, buff *bytes.Buffer, expected string) {
|
||||
t.Helper()
|
||||
|
||||
if got := buff.String(); got != expected {
|
||||
t.Fatalf("expected middleware to run before the error handler, expected: '%s' but got: '%s'", expected, got)
|
||||
}
|
||||
|
||||
buff.Reset()
|
||||
}
|
||||
|
||||
func TestPartyOnErrorCode(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.Configure(iris.WithFireMethodNotAllowed)
|
||||
|
||||
globalNotFoundResponse := "custom not found"
|
||||
app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) {
|
||||
ctx.WriteString(globalNotFoundResponse)
|
||||
})
|
||||
|
||||
globalMethodNotAllowedResponse := "global: method not allowed"
|
||||
app.OnErrorCode(iris.StatusMethodNotAllowed, func(ctx iris.Context) {
|
||||
ctx.WriteString(globalMethodNotAllowedResponse)
|
||||
})
|
||||
|
||||
app.Get("/path", h)
|
||||
|
||||
usersResponse := "users: method allowed"
|
||||
users := app.Party("/users")
|
||||
users.OnErrorCode(iris.StatusMethodNotAllowed, func(ctx iris.Context) {
|
||||
ctx.WriteString(usersResponse)
|
||||
})
|
||||
users.Get("/", h)
|
||||
write400 := func(ctx iris.Context) { ctx.StatusCode(iris.StatusBadRequest) }
|
||||
// test setting the error code from a handler.
|
||||
users.Get("/badrequest", write400)
|
||||
|
||||
usersuserResponse := "users:user: method allowed"
|
||||
user := users.Party("/{id:int}")
|
||||
user.OnErrorCode(iris.StatusMethodNotAllowed, func(ctx iris.Context) {
|
||||
ctx.WriteString(usersuserResponse)
|
||||
})
|
||||
usersuserNotFoundResponse := "users:user: not found"
|
||||
user.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) {
|
||||
ctx.WriteString(usersuserNotFoundResponse)
|
||||
})
|
||||
user.Get("/", h)
|
||||
user.Get("/ab/badrequest", write400)
|
||||
|
||||
friends := users.Party("/friends")
|
||||
friends.Get("/{id:int}", h)
|
||||
|
||||
e := httptest.New(t, app)
|
||||
|
||||
e.GET("/notfound").Expect().Status(iris.StatusNotFound).Body().Equal(globalNotFoundResponse)
|
||||
e.POST("/path").Expect().Status(iris.StatusMethodNotAllowed).Body().Equal(globalMethodNotAllowedResponse)
|
||||
e.GET("/path").Expect().Status(iris.StatusOK).Body().Equal("/path")
|
||||
|
||||
e.POST("/users").Expect().Status(iris.StatusMethodNotAllowed).
|
||||
Body().Equal(usersResponse)
|
||||
|
||||
e.POST("/users/42").Expect().Status(iris.StatusMethodNotAllowed).
|
||||
Body().Equal(usersuserResponse)
|
||||
|
||||
e.GET("/users/42").Expect().Status(iris.StatusOK).
|
||||
Body().Equal("/users/42")
|
||||
e.GET("/users/ab").Expect().Status(iris.StatusNotFound).Body().Equal(usersuserNotFoundResponse)
|
||||
// inherit the parent.
|
||||
e.GET("/users/42/friends/dsa").Expect().Status(iris.StatusNotFound).Body().Equal(usersuserNotFoundResponse)
|
||||
|
||||
// if not registered to the party, then the root is taking action.
|
||||
e.GET("/users/42/ab/badrequest").Expect().Status(iris.StatusBadRequest).Body().Equal(http.StatusText(iris.StatusBadRequest))
|
||||
|
||||
// if not registered to the party, and not in root, then just write the status text (fallback behavior)
|
||||
e.GET("/users/badrequest").Expect().Status(iris.StatusBadRequest).
|
||||
Body().Equal(http.StatusText(iris.StatusBadRequest))
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package router
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/context"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
Reference in New Issue
Block a user