1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-24 04:15:56 +00:00

add the stale release

This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-08-12 23:41:20 +03:00
parent 535fb6dc0d
commit 2a4ce876b6
793 changed files with 188 additions and 52415 deletions

View File

@@ -1,173 +0,0 @@
package errgroup
import (
"errors"
"fmt"
"strings"
"testing"
)
func TestErrorError(t *testing.T) {
testErr := errors.New("error")
err := &Error{Err: testErr}
if expected, got := testErr.Error(), err.Error(); expected != got {
t.Fatalf("expected %s but got %s", expected, got)
}
}
func TestErrorUnwrap(t *testing.T) {
wrapped := errors.New("unwrap")
err := &Error{Err: fmt.Errorf("this wraps:%w", wrapped)}
if expected, got := wrapped, errors.Unwrap(err); expected != got {
t.Fatalf("expected %#+v but got %#+v", expected, got)
}
}
func TestErrorIs(t *testing.T) {
testErr := errors.New("is")
err := &Error{Err: fmt.Errorf("this is: %w", testErr)}
if expected, got := true, errors.Is(err, testErr); expected != got {
t.Fatalf("expected %v but got %v", expected, got)
}
}
func TestErrorAs(t *testing.T) {
testErr := errors.New("as")
err := &Error{Err: testErr}
if expected, got := true, errors.As(err, &testErr); expected != got {
t.Fatalf("[testErr as err] expected %v but got %v", expected, got)
}
if expected, got := true, errors.As(testErr, &err); expected != got {
t.Fatalf("[err as testErr] expected %v but got %v", expected, got)
}
}
func TestGroupError(t *testing.T) {
g := New(0)
tests := []string{"error 1", "error 2", "error 3"}
for _, tt := range tests {
g.Add(errors.New(tt))
}
if expected, got := strings.Join(tests, "\n"), g.Error(); expected != got {
t.Fatalf("expected '%s' but got '%s'", expected, got)
}
}
func TestGroup(t *testing.T) {
const (
apiErrorsType = iota + 1
childAPIErrorsType
childAPIErrors2Type = "string type 1"
childAPIErrors2Type1 = "string type 2"
apiErrorsText = "apiErrors error 1"
childAPIErrorsText = "apiErrors:child error 1"
childAPIErrors2Text = "apiErrors:child2 error 1"
childAPIErrors2Text1 = "apiErrors:child2_1 error 1"
)
g := New(nil)
apiErrorsGroup := g.Group(apiErrorsType)
apiErrorsGroup.Errf(apiErrorsText)
childAPIErrorsGroup := apiErrorsGroup.Group(childAPIErrorsType)
childAPIErrorsGroup.Addf(childAPIErrorsText)
childAPIErrorsGroup2 := apiErrorsGroup.Group(childAPIErrors2Type)
childAPIErrorsGroup2.Addf(childAPIErrors2Text)
childAPIErrorsGroup2Group1 := childAPIErrorsGroup2.Group(childAPIErrors2Type1)
childAPIErrorsGroup2Group1.Addf(childAPIErrors2Text1)
if apiErrorsGroup.Type != apiErrorsType {
t.Fatal("invalid type")
}
if childAPIErrorsGroup.Type != childAPIErrorsType {
t.Fatal("invalid type")
}
if childAPIErrorsGroup2.Type != childAPIErrors2Type {
t.Fatal("invalid type")
}
if childAPIErrorsGroup2Group1.Type != childAPIErrors2Type1 {
t.Fatal("invalid type")
}
if expected, got := 2, len(apiErrorsGroup.children); expected != got {
t.Fatalf("expected %d but got %d", expected, got)
}
if expected, got := 0, len(childAPIErrorsGroup.children); expected != got {
t.Fatalf("expected %d but got %d", expected, got)
}
if expected, got := 1, len(childAPIErrorsGroup2.children); expected != got {
t.Fatalf("expected %d but got %d", expected, got)
}
if expected, got := 0, len(childAPIErrorsGroup2Group1.children); expected != got {
t.Fatalf("expected %d but got %d", expected, got)
}
if expected, got := 1, apiErrorsGroup.index; expected != got {
t.Fatalf("expected index %d but got %d", expected, got)
}
if expected, got := 2, childAPIErrorsGroup.index; expected != got {
t.Fatalf("expected index %d but got %d", expected, got)
}
if expected, got := 3, childAPIErrorsGroup2.index; expected != got {
t.Fatalf("expected index %d but got %d", expected, got)
}
if expected, got := 4, childAPIErrorsGroup2Group1.index; expected != got {
t.Fatalf("expected index %d but got %d", expected, got)
}
t.Run("Error", func(t *testing.T) {
if expected, got :=
strings.Join([]string{apiErrorsText, childAPIErrorsText, childAPIErrors2Text, childAPIErrors2Text1}, delim), g.Error(); expected != got {
t.Fatalf("expected '%s' but got '%s'", expected, got)
}
})
t.Run("Walk", func(t *testing.T) {
expectedEntries := 4
_ = Walk(g, func(typ interface{}, err error) {
g.IncludeChildren = false
childAPIErrorsGroup.IncludeChildren = false
childAPIErrorsGroup2.IncludeChildren = false
childAPIErrorsGroup2Group1.IncludeChildren = false
expectedEntries--
var expected string
switch typ {
case apiErrorsType:
expected = apiErrorsText
case childAPIErrorsType:
expected = childAPIErrorsText
case childAPIErrors2Type:
expected = childAPIErrors2Text
case childAPIErrors2Type1:
expected = childAPIErrors2Text1
}
if got := err.Error(); expected != got {
t.Fatalf("[%v] expected '%s' but got '%s'", typ, expected, got)
}
})
if expectedEntries != 0 {
t.Fatalf("not valid number of errors [...%d]", expectedEntries)
}
g.IncludeChildren = true
childAPIErrorsGroup.IncludeChildren = true
childAPIErrorsGroup2.IncludeChildren = true
childAPIErrorsGroup2Group1.IncludeChildren = true
})
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"net/http"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
)
// FromStd converts native http.Handler & http.HandlerFunc to context.Handler.

View File

@@ -1,71 +0,0 @@
// black-box testing
package handlerconv_test
import (
stdContext "context"
"net/http"
"testing"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/core/handlerconv"
"github.com/kataras/iris/v12/httptest"
)
func TestFromStd(t *testing.T) {
expected := "ok"
std := func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(expected))
if err != nil {
t.Fatal(err)
}
}
h := handlerconv.FromStd(http.HandlerFunc(std))
hFunc := handlerconv.FromStd(std)
app := iris.New()
app.Get("/handler", h)
app.Get("/func", hFunc)
e := httptest.New(t, app)
e.GET("/handler").
Expect().Status(iris.StatusOK).Body().Equal(expected)
e.GET("/func").
Expect().Status(iris.StatusOK).Body().Equal(expected)
}
func TestFromStdWithNext(t *testing.T) {
basicauth := "secret"
passed := "ok"
type contextKey string
stdWNext := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if username, password, ok := r.BasicAuth(); ok &&
username == basicauth && password == basicauth {
ctx := stdContext.WithValue(r.Context(), contextKey("key"), "ok")
next.ServeHTTP(w, r.WithContext(ctx))
return
}
w.WriteHeader(iris.StatusForbidden)
}
h := handlerconv.FromStdWithNext(stdWNext)
next := func(ctx *context.Context) {
ctx.WriteString(ctx.Request().Context().Value(contextKey("key")).(string))
}
app := iris.New()
app.Get("/handlerwithnext", h, next)
e := httptest.New(t, app)
e.GET("/handlerwithnext").
Expect().Status(iris.StatusForbidden)
e.GET("/handlerwithnext").WithBasicAuth(basicauth, basicauth).
Expect().Status(iris.StatusOK).Body().Equal(passed)
}

View File

@@ -8,7 +8,7 @@ import (
"strings"
"time"
"github.com/kataras/iris/v12/core/netutil"
"github.com/kataras/iris/core/netutil"
)
func singleJoiningSlash(a, b string) string {

View File

@@ -1,69 +0,0 @@
// black-box testing
package host_test
import (
"net"
"net/url"
"testing"
"time"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/core/host"
"github.com/kataras/iris/v12/httptest"
)
func TestProxy(t *testing.T) {
expectedIndex := "ok /"
expectedAbout := "ok /about"
unexpectedRoute := "unexpected"
// proxySrv := iris.New()
u, err := url.Parse("https://localhost:4444")
if err != nil {
t.Fatalf("%v while parsing url", err)
}
proxy := host.NewProxy("", u)
addr := &net.TCPAddr{
IP: net.IPv4(127, 0, 0, 1),
Port: 0,
}
listener, err := net.ListenTCP("tcp", addr)
if err != nil {
t.Fatalf("%v while creating listener", err)
}
go proxy.Serve(listener) // should be localhost/127.0.0.1:80 but travis throws permission denied.
t.Log(listener.Addr().String())
<-time.After(time.Second)
t.Log(listener.Addr().String())
app := iris.New()
app.Get("/", func(ctx *context.Context) {
ctx.WriteString(expectedIndex)
})
app.Get("/about", func(ctx *context.Context) {
ctx.WriteString(expectedAbout)
})
app.OnErrorCode(iris.StatusNotFound, func(ctx *context.Context) {
ctx.WriteString(unexpectedRoute)
})
l, err := net.Listen("tcp", "localhost:4444") // should be localhost/127.0.0.1:443 but travis throws permission denied.
if err != nil {
t.Fatalf("%v while creating tcp4 listener for new tls local test listener", err)
}
// main server
go app.Run(iris.Listener(httptest.NewLocalTLSListener(l)), iris.WithoutStartupLog) // nolint:errcheck
e := httptest.NewInsecure(t, httptest.URL("http://"+listener.Addr().String()))
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedIndex)
e.GET("/about").Expect().Status(iris.StatusOK).Body().Equal(expectedAbout)
e.GET("/notfound").Expect().Status(iris.StatusNotFound).Body().Equal(unexpectedRoute)
}

View File

@@ -14,7 +14,7 @@ import (
"sync/atomic"
"time"
"github.com/kataras/iris/v12/core/netutil"
"github.com/kataras/iris/core/netutil"
"golang.org/x/crypto/acme/autocert"
)

View File

@@ -1,112 +0,0 @@
// white-box testing
package host
import (
"context"
"fmt"
"log"
"net"
"net/http"
"os"
"time"
)
func ExampleSupervisor_RegisterOnError() {
su := New(&http.Server{Addr: ":8273", Handler: http.DefaultServeMux})
su.RegisterOnError(func(err error) {
fmt.Println(err.Error())
})
su.RegisterOnError(func(err error) {
fmt.Println(err.Error())
})
su.RegisterOnError(func(err error) {
fmt.Println(err.Error())
})
go su.ListenAndServe()
time.Sleep(1 * time.Second)
if err := su.Shutdown(context.TODO()); err != nil {
panic(err)
}
time.Sleep(1 * time.Second)
// Output:
// http: Server closed
// http: Server closed
// http: Server closed
}
type myTestTask struct {
restartEvery time.Duration
maxRestarts int
logger *log.Logger
}
func (m myTestTask) OnServe(host TaskHost) {
host.Supervisor.DeferFlow() // don't exit on underline server's Shutdown.
ticker := time.NewTicker(m.restartEvery)
defer ticker.Stop()
rans := 0
for range ticker.C {
exitAfterXRestarts := m.maxRestarts
if rans == exitAfterXRestarts {
m.logger.Println("exit")
ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
defer cancel()
_ = host.Supervisor.Shutdown(ctx) // total shutdown
host.Supervisor.RestoreFlow() // free to exit (if shutdown)
return
}
rans++
m.logger.Println(fmt.Sprintf("closed %d times", rans))
host.Shutdown(context.TODO())
startDelay := 2 * time.Second
time.AfterFunc(startDelay, func() {
m.logger.Println("restart")
if err := host.Serve(); err != nil { // restart
panic(err)
}
})
}
}
func ExampleSupervisor_RegisterOnServe() {
h := New(&http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
}),
})
logger := log.New(os.Stdout, "Supervisor: ", 0)
mytask := myTestTask{
restartEvery: 3 * time.Second,
maxRestarts: 2,
logger: logger,
}
h.RegisterOnServe(mytask.OnServe)
ln, err := net.Listen("tcp4", ":9394")
if err != nil {
panic(err.Error())
}
logger.Println("server started...")
h.Serve(ln)
// Output:
// Supervisor: server started...
// Supervisor: closed 1 times
// Supervisor: restart
// Supervisor: closed 2 times
// Supervisor: restart
// Supervisor: exit
}

View File

@@ -1,119 +0,0 @@
// white-box testing
package host
import (
"bytes"
"context"
"crypto/tls"
"log"
"net"
"net/http"
"strings"
"sync"
"testing"
"github.com/iris-contrib/httpexpect/v2"
)
const (
debug = false
)
func newTester(t *testing.T, baseURL string, handler http.Handler) *httpexpect.Expect {
var transporter http.RoundTripper
if strings.HasPrefix(baseURL, "http") { // means we are testing real serve time
transporter = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
} else { // means we are testing the handler itself
transporter = httpexpect.NewBinder(handler)
}
testConfiguration := httpexpect.Config{
BaseURL: baseURL,
Client: &http.Client{
Transport: transporter,
Jar: httpexpect.NewJar(),
},
Reporter: httpexpect.NewAssertReporter(t),
}
if debug {
testConfiguration.Printers = []httpexpect.Printer{
httpexpect.NewDebugPrinter(t, true),
}
}
return httpexpect.WithConfig(testConfiguration)
}
func testSupervisor(t *testing.T, creator func(*http.Server, []func(TaskHost)) *Supervisor) {
loggerOutput := &bytes.Buffer{}
logger := log.New(loggerOutput, "", 0)
mu := new(sync.RWMutex)
const (
expectedHelloMessage = "Hello\n"
)
// http routing
expectedBody := "this is the response body\n"
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(expectedBody))
if err != nil {
t.Fatal(err)
}
})
// host (server wrapper and adapter) construction
srv := &http.Server{Handler: mux, ErrorLog: logger}
addr := "localhost:5525"
// serving
ln, err := net.Listen("tcp4", addr)
if err != nil {
t.Fatal(err)
}
helloMe := func(_ TaskHost) {
mu.Lock()
logger.Print(expectedHelloMessage)
mu.Unlock()
}
host := creator(srv, []func(TaskHost){helloMe})
defer host.Shutdown(context.TODO())
go host.Serve(ln)
// http testsing and various calls
// no need for time sleep because the following will take some time by theirselves
tester := newTester(t, "http://"+addr, mux)
tester.Request("GET", "/").Expect().Status(http.StatusOK).Body().Equal(expectedBody)
// WARNING: Data Race here because we try to read the logs
// but it's "safe" here.
// testing Task (recorded) message:
mu.RLock()
got := loggerOutput.String()
mu.RUnlock()
if expectedHelloMessage != got {
t.Fatalf("expected hello Task's message to be '%s' but got '%s'", expectedHelloMessage, got)
}
}
func TestSupervisor(t *testing.T) {
testSupervisor(t, func(srv *http.Server, tasks []func(TaskHost)) *Supervisor {
su := New(srv)
for _, t := range tasks {
su.RegisterOnServe(t)
}
return su
})
}

View File

@@ -13,7 +13,7 @@ import (
"runtime"
"time"
"github.com/kataras/iris/v12/core/netutil"
"github.com/kataras/iris/core/netutil"
)
// WriteStartupLogOnServe is a task which accepts a logger(io.Writer)

View File

@@ -1,167 +0,0 @@
// white-box testing
package memstore
import (
"bytes"
"encoding/json"
"fmt"
"testing"
)
type myTestObject struct {
Name string `json:"name"`
}
func TestMuttable(t *testing.T) {
var p Store
// slice
p.Set("slice", []myTestObject{{"value 1"}, {"value 2"}})
v := p.Get("slice").([]myTestObject)
v[0].Name = "modified"
vv := p.Get("slice").([]myTestObject)
if vv[0].Name != "modified" {
t.Fatalf("expected slice to be muttable but caller was not able to change its value")
}
// map
p.Set("map", map[string]myTestObject{"key 1": {"value 1"}, "key 2": {"value 2"}})
vMap := p.Get("map").(map[string]myTestObject)
vMap["key 1"] = myTestObject{"modified"}
vvMap := p.Get("map").(map[string]myTestObject)
if vvMap["key 1"].Name != "modified" {
t.Fatalf("expected map to be muttable but caller was not able to change its value")
}
// object pointer of a value, it can change like maps or slices and arrays.
p.Set("objp", &myTestObject{"value"})
// we expect pointer here, as we set it.
vObjP := p.Get("objp").(*myTestObject)
vObjP.Name = "modified"
vvObjP := p.Get("objp").(*myTestObject)
if vvObjP.Name != "modified" {
t.Fatalf("expected objp to be muttable but caller was able to change its value")
}
}
func TestImmutable(t *testing.T) {
var p Store
// slice
p.SetImmutable("slice", []myTestObject{{"value 1"}, {"value 2"}})
v := p.Get("slice").([]myTestObject)
v[0].Name = "modified"
vv := p.Get("slice").([]myTestObject)
if vv[0].Name == "modified" {
t.Fatalf("expected slice to be immutable but caller was able to change its value")
}
// map
p.SetImmutable("map", map[string]myTestObject{"key 1": {"value 1"}, "key 2": {"value 2"}})
vMap := p.Get("map").(map[string]myTestObject)
vMap["key 1"] = myTestObject{"modified"}
vvMap := p.Get("map").(map[string]myTestObject)
if vvMap["key 1"].Name == "modified" {
t.Fatalf("expected map to be immutable but caller was able to change its value")
}
// object value, it's immutable at all cases.
p.SetImmutable("obj", myTestObject{"value"})
vObj := p.Get("obj").(myTestObject)
vObj.Name = "modified"
vvObj := p.Get("obj").(myTestObject)
if vvObj.Name == "modified" {
t.Fatalf("expected obj to be immutable but caller was able to change its value")
}
// object pointer of a value, it's immutable at all cases.
p.SetImmutable("objp", &myTestObject{"value"})
// we expect no pointer here if SetImmutable.
// so it can't be changed by-design
vObjP := p.Get("objp").(myTestObject)
vObjP.Name = "modified"
vvObjP := p.Get("objp").(myTestObject)
if vvObjP.Name == "modified" {
t.Fatalf("expected objp to be immutable but caller was able to change its value")
}
}
func TestImmutableSetOnlyWithSetImmutable(t *testing.T) {
var p Store
p.SetImmutable("objp", &myTestObject{"value"})
p.Set("objp", &myTestObject{"modified"})
vObjP := p.Get("objp").(myTestObject)
if vObjP.Name == "modified" {
t.Fatalf("caller should not be able to change the immutable entry with a simple `Set`")
}
p.SetImmutable("objp", &myTestObject{"value with SetImmutable"})
vvObjP := p.Get("objp").(myTestObject)
if vvObjP.Name != "value with SetImmutable" {
t.Fatalf("caller should be able to change the immutable entry with a `SetImmutable`")
}
}
func TestGetInt64Default(t *testing.T) {
var p Store
p.Set("a uint16", uint16(2))
if v := p.GetInt64Default("a uint16", 0); v != 2 {
t.Fatalf("unexpected value of %d", v)
}
}
func TestJSON(t *testing.T) {
var p Store
p.Set("key1", "value1")
p.Set("key2", 2)
p.Set("key3", myTestObject{Name: "makis"})
b, err := json.Marshal(p)
if err != nil {
t.Fatal(err)
}
expectedJSON := []byte(`[{"key":"key1","value":"value1"},{"key":"key2","value":2},{"key":"key3","value":{"name":"makis"}}]`)
if !bytes.Equal(b, expectedJSON) {
t.Fatalf("expected: %s but got: %s", string(expectedJSON), string(b))
}
var newStore Store
if err = json.Unmarshal(b, &newStore); err != nil {
t.Fatal(err)
}
for i, v := range newStore {
expected, got := p.Get(v.Key), v.ValueRaw
if ex, g := fmt.Sprintf("%v", expected), fmt.Sprintf("%v", got); ex != g {
if _, isMap := got.(map[string]interface{}); isMap {
// was struct but converted into map (as expected).
b1, _ := json.Marshal(expected)
b2, _ := json.Marshal(got)
if !bytes.Equal(b1, b2) {
t.Fatalf("[%d] JSON expected: %s but got: %s", i, string(b1), string(b2))
}
continue
}
t.Fatalf("[%d] expected: %s but got: %s", i, ex, g)
}
}
}

View File

@@ -1,43 +0,0 @@
package netutil
import (
"testing"
)
func TestIsLoopbackHost(t *testing.T) {
tests := []struct {
host string
valid bool
}{
{"subdomain.127.0.0.1:8080", true},
{"subdomain.127.0.0.1", true},
{"subdomain.localhost:8080", true},
{"subdomain.localhost", true},
{"subdomain.127.0000.0000.1:8080", true},
{"subdomain.127.0000.0000.1", true},
{"subdomain.127.255.255.254:8080", true},
{"subdomain.127.255.255.254", true},
{"subdomain.0000:0:0000::01.1:8080", false},
{"subdomain.0000:0:0000::01", false},
{"subdomain.0000:0:0000::01.1:8080", false},
{"subdomain.0000:0:0000::01", false},
{"subdomain.0000:0000:0000:0000:0000:0000:0000:0001:8080", true},
{"subdomain.0000:0000:0000:0000:0000:0000:0000:0001", false},
{"subdomain.example:8080", false},
{"subdomain.example", false},
{"subdomain.example.com:8080", false},
{"subdomain.example.com", false},
{"subdomain.com", false},
{"subdomain", false},
{".subdomain", false},
{"127.0.0.1.com", false},
}
for i, tt := range tests {
if expected, got := tt.valid, IsLoopbackHost(tt.host); expected != got {
t.Fatalf("[%d] expected %t but got %t for %s", i, expected, got, tt.host)
}
}
}

View File

@@ -1,62 +0,0 @@
package netutil
import (
"net"
"testing"
)
func TestIP(t *testing.T) {
privateRanges := []IPRange{
{
Start: net.ParseIP("10.0.0.0"),
End: net.ParseIP("10.255.255.255"),
},
{
Start: net.ParseIP("100.64.0.0"),
End: net.ParseIP("100.127.255.255"),
},
{
Start: net.ParseIP("172.16.0.0"),
End: net.ParseIP("172.31.255.255"),
},
{
Start: net.ParseIP("192.0.0.0"),
End: net.ParseIP("192.0.0.255"),
},
{
Start: net.ParseIP("192.168.0.0"),
End: net.ParseIP("192.168.255.255"),
},
{
Start: net.ParseIP("198.18.0.0"),
End: net.ParseIP("198.19.255.255"),
},
}
addresses := []string{
"201.37.138.59",
"159.117.3.153",
"166.192.97.84",
"225.181.213.210",
"124.50.84.134",
"87.53.250.102",
"106.79.33.62",
"242.120.17.144",
"131.179.101.254",
"103.11.11.174",
"115.97.0.114",
"219.202.120.251",
"37.72.123.120",
"154.94.78.101",
"126.105.144.250",
}
got, ok := GetIPAddress(addresses, privateRanges)
if !ok {
t.Logf("expected addr to be matched")
}
if expected := "126.105.144.250"; expected != got {
t.Logf("expected addr to be found: %s but got: %s", expected, got)
}
}

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,7 @@ import (
"sync"
"time"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
)
const indexName = "/index.html"

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,7 @@ import (
"mime"
"path/filepath"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
)
var types = map[string]string{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,7 @@ import (
"strings"
"sync"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
"github.com/schollz/closestmatch"
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ package router
import (
"strings"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
)
const (