-
Notifications
You must be signed in to change notification settings - Fork 12
/
policy_nativerouter_test.go
183 lines (161 loc) · 5.6 KB
/
policy_nativerouter_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package iris_test
import (
"net/http"
"testing"
. "gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/httptest"
)
// This will be removed at the final release
// it's here just for my tests
// it will may transferred to the (advanced) examples repository
// in order to show the users how they can adapt any third-party router.
// They can also view the ./adaptors/httprouter and ./adaptors/gorillamux.
func newTestNativeRouter() Policies {
fireMethodNotAllowed := false
return Policies{
EventPolicy: EventPolicy{
Boot: func(s *Framework) {
fireMethodNotAllowed = s.Config.FireMethodNotAllowed
},
},
RouterReversionPolicy: RouterReversionPolicy{
// path normalization done on iris' side
StaticPath: func(path string) string { return path },
WildcardPath: func(requestPath string, paramName string) string { return requestPath },
URLPath: func(r RouteInfo, args ...string) string {
if r == nil {
return ""
}
// note:
// as we already know, net/http servemux doesn't provides parameterized paths so we will
// use the passed args(if any) to build the url query
path := r.Path()
if len(args) > 0 {
if len(args)%2 != 0 {
// key=value
// so the result of len args should be %2==0.
// if not return just the path.
return path
}
path += "?"
for i := 0; i < len(args)-1; i++ {
path += args[i] + "=" + args[i+1]
i++
if i != len(args)-1 {
path += "&"
}
}
}
return path
},
},
RouterBuilderPolicy: func(repo RouteRepository, context ContextPool) http.Handler {
servemux := http.NewServeMux()
noIndexRegistered := true
repo.Visit(func(route RouteInfo) {
path := route.Path()
if path == "/" {
noIndexRegistered = false // this goes before the handlefunc("/")
}
if path[len(path)-1] != '/' { // append a slash (net/http works this way)
path += "/"
repo.ChangePath(route, path)
}
servemux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
ctx := context.Acquire(w, r)
if ctx.Method() == route.Method() || ctx.Method() == MethodOptions && route.HasCors() {
ctx.Middleware = route.Middleware()
recorder := ctx.Recorder()
ctx.Do()
statusCode := recorder.StatusCode()
if statusCode >= 400 { // if we have an error status code try to find a custom error handler
errorHandler := ctx.Framework().Errors.Get(statusCode)
if errorHandler != nil {
// it will reset the response and write its own response by the user's handler
errorHandler.Serve(ctx)
}
}
} else if fireMethodNotAllowed {
ctx.EmitError(StatusMethodNotAllowed) // fire method not allowed if enabled
} else { // else fire not found
ctx.EmitError(StatusNotFound)
}
context.Release(ctx)
})
})
// ok, we can't bypass the net/http server.go's err handlers
// we have two options:
// - create the mux by ourselve, not an ideal because we already done two of them.
// - create a new response writer which will check once if user has registered error handler,if yes write that response instead.
// - on "/" path(which net/http fallbacks if no any registered route handler found) make if requested_path != "/" or ""
// and emit the 404 error, but for the rest of the custom errors...?
// - use our custom context's recorder to record the status code, this will be a bit slower solution(maybe not)
// but it covers all our scenarios.
if noIndexRegistered {
servemux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
context.Run(w, r, func(ctx *Context) {
ctx.EmitError(StatusNotFound)
})
})
}
return servemux
},
}
}
func h(ctx *Context) {
ctx.WriteString("hello from " + ctx.Path())
}
type testNativeRoute struct {
method, path, body string
status int
}
func TestNativeRouter(t *testing.T) {
expectedWrongMethodStatus := StatusNotFound
app := New(Configuration{FireMethodNotAllowed: true})
app.Adapt(newTestNativeRouter())
// 404 or 405
if app.Config.FireMethodNotAllowed {
expectedWrongMethodStatus = StatusMethodNotAllowed
}
var testRoutes = []testNativeRoute{
{"GET", "/hi", "Should be /hi/ \nhello from /hi/", StatusOK},
{"GET", "/other", "Should be /other/ \nhello from /other/", StatusOK},
{"GET", "/hi/you", "Should be /hi/you/ \nhello from /hi/you/", StatusOK},
{"POST", "/hey", "hello from /hey/", StatusOK},
{"GET", "/hey", "Method Not Allowed", expectedWrongMethodStatus},
{"GET", "/doesntexists", "<b>Custom 404 page</b>", StatusNotFound},
}
app.OnError(404, func(ctx *Context) {
ctx.HTML(404, "<b>Custom 404 page</b>")
})
app.Get("/hi", func(ctx *Context) {
ctx.Writef("Should be /hi/ \n")
ctx.Next()
}, h)
app.Get("/other", func(ctx *Context) {
ctx.Writef("Should be /other/ \n")
ctx.Next()
}, h)
app.Get("/hi/you", func(ctx *Context) {
ctx.Writef("Should be /hi/you/ \n")
ctx.Next()
}, h)
app.Post("/hey", h)
app.None("/profile", func(ctx *Context) {
userid, _ := ctx.URLParamInt("user_id")
ref := ctx.URLParam("ref")
ctx.Writef("%s\n%d", userid, ref)
}).ChangeName("profile")
e := httptest.New(app, t)
expected := "/profile/?user_id=42&ref=iris-go&anything=something"
if got := app.Path("profile", "user_id", 42, "ref", "iris-go", "anything", "something"); got != expected {
t.Fatalf("URLPath expected %s but got %s", expected, got)
}
for _, r := range testRoutes {
// post should be passed with ending / here, it's not iris-specific.
if r.method == "POST" {
r.path += "/"
}
e.Request(r.method, r.path).Expect().Status(r.status).Body().Equal(r.body).Raw()
}
}