Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: server/router/router_test.go

Issue 2043423004: Make HTTP middleware easier to use (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: router: Improve tests Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « server/router/router.go ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package router
6
7 import (
8 "io"
9 "io/ioutil"
10 "net/http"
11 "net/http/httptest"
12 "strings"
13 "testing"
14
15 "golang.org/x/net/context"
16
17 . "github.com/smartystreets/goconvey/convey"
18 )
19
20 func TestRouter(t *testing.T) {
21 t.Parallel()
22
23 outputKey := "output"
24 appendValue := func(c context.Context, key string, val string) context.C ontext {
25 var current []string
26 if v := c.Value(key); v != nil {
27 current = v.([]string)
28 }
29 return context.WithValue(c, key, append(current, val))
30 }
31 a := func(c *Context, next Handler) {
32 c.Context = appendValue(c, outputKey, "a:before")
33 next(c)
34 c.Context = appendValue(c, outputKey, "a:after")
35 }
36 b := func(c *Context, next Handler) {
37 c.Context = appendValue(c, outputKey, "b:before")
38 next(c)
39 c.Context = appendValue(c, outputKey, "b:after")
40 }
41 c := func(c *Context, next Handler) {
42 c.Context = appendValue(c, outputKey, "c")
43 next(c)
44 }
45 d := func(c *Context, next Handler) {
46 next(c)
47 c.Context = appendValue(c, outputKey, "d")
48 }
49 stop := func(_ *Context, _ Handler) {}
50 handler := func(c *Context) {
51 c.Context = appendValue(c, outputKey, "handler")
52 }
53
54 Convey("Router", t, func() {
55 r := New()
56
57 Convey("New", func() {
58 Convey("Should initialize non-nil httprouter.Router", fu nc() {
59 So(r.hrouter, ShouldNotBeNil)
60 })
61 })
62
63 Convey("Use", func() {
64 Convey("Should append middleware", func() {
65 So(len(r.middleware), ShouldEqual, 0)
66 r.Use(MiddlewareChain{a, b})
67 So(len(r.middleware), ShouldEqual, 2)
68 })
69 })
70
71 Convey("Subrouter", func() {
72 Convey("Should create new router with values from origin al router", func() {
73 r.BasePath = "/foo/"
74 r.Use(MiddlewareChain{a, b})
75 r2 := r.Subrouter("/bar")
76 So(r.hrouter, ShouldPointTo, r2.hrouter)
77 So(r2.BasePath, ShouldEqual, "/foo/bar/")
78 So(&r.middleware[0], ShouldNotEqual, &r2.middlew are[0])
79 So(&r.middleware[1], ShouldNotEqual, &r2.middlew are[1])
80 So(len(r.middleware), ShouldEqual, len(r2.middle ware))
81 So(r.middleware[0], ShouldEqual, r2.middleware[0 ])
82 So(r.middleware[1], ShouldEqual, r2.middleware[1 ])
83 })
84 })
85
86 Convey("Handle", func() {
87 Convey("Should not modify existing empty r.middleware sl ice", func() {
88 So(len(r.middleware), ShouldEqual, 0)
89 r.Handle("GET", "/bar", MiddlewareChain{b, c}, h andler)
90 So(len(r.middleware), ShouldEqual, 0)
91 })
92
93 Convey("Should not modify existing r.middleware slice", func() {
94 r.Use(MiddlewareChain{a})
95 So(len(r.middleware), ShouldEqual, 1)
96 r.Handle("GET", "/bar", MiddlewareChain{b, c}, h andler)
97 So(len(r.middleware), ShouldEqual, 1)
98 })
99 })
100
101 Convey("run", func() {
102 ctx := &Context{Context: context.Background()}
103
104 Convey("Should execute handler when using nil middleware s", func() {
105 run(ctx, nil, nil, handler)
106 So(ctx.Value(outputKey).([]string), ShouldResemb le, []string{"handler"})
nodir 2016/06/16 22:19:00 ctx.Value(outputKey).([]string) casts the value fr
nishanths 2016/06/16 22:24:21 Thanks. Done.
107 })
108
109 Convey("Should execute middlewares and handler in order" , func() {
110 m := MiddlewareChain{a, b, c}
111 n := MiddlewareChain{d}
112 run(ctx, m, n, handler)
113 So(ctx.Value(outputKey).([]string), ShouldResemb le,
114 []string{"a:before", "b:before", "c", "h andler", "d", "b:after", "a:after"},
115 )
116 })
117
118 Convey("Should not execute upcoming middleware/handlers if next is not called", func() {
119 mc := MiddlewareChain{a, stop, b}
120 run(ctx, mc, nil, handler)
121 So(ctx.Value(outputKey).([]string), ShouldResemb le, []string{"a:before", "a:after"})
122 })
123 })
124
125 Convey("ServeHTTP", func() {
126 ts := httptest.NewServer(r)
127 client := &http.Client{}
128 a := func(c *Context, next Handler) {
129 c.Context = appendValue(c, outputKey, "a:before" )
130 next(c)
131 c.Context = appendValue(c, outputKey, "a:after")
132 io.WriteString(c, strings.Join(c.Value(outputKey ).([]string), ","))
133 }
134
135 Convey("Should execute middleware registered in Use and Handle in order", func() {
136 r.Use(MiddlewareChain{a})
137 r.GET("/ab", MiddlewareChain{b}, handler)
138 res, err := client.Get(ts.URL + "/ab")
139 So(err, ShouldBeNil)
140 defer res.Body.Close()
141 So(res.StatusCode, ShouldEqual, http.StatusOK)
142 p, err := ioutil.ReadAll(res.Body)
143 So(err, ShouldBeNil)
144 So(string(p), ShouldEqual, strings.Join(
145 []string{"a:before", "b:before", "handle r", "b:after", "a:after"},
146 ",",
147 ))
148 })
149
150 Convey("Should return method not allowed for existing pa th but wrong method in request", func() {
151 r.POST("/comment", nil, handler)
152 res, err := client.Get(ts.URL + "/comment")
153 So(err, ShouldBeNil)
154 defer res.Body.Close()
155 So(res.StatusCode, ShouldEqual, http.StatusMetho dNotAllowed)
156 })
157
158 Convey("Should return expected response from handler", f unc() {
159 handler := func(c *Context) {
160 c.Write([]byte("Hello, " + c.Params[0].V alue))
161 }
162 r.GET("/hello/:name", MiddlewareChain{c, d}, han dler)
163 res, err := client.Get(ts.URL + "/hello/世界")
164 So(err, ShouldBeNil)
165 defer res.Body.Close()
166 So(res.StatusCode, ShouldEqual, http.StatusOK)
167 p, err := ioutil.ReadAll(res.Body)
168 So(err, ShouldBeNil)
169 So(string(p), ShouldEqual, "Hello, 世界")
170 })
171
172 Reset(func() {
173 ts.Close()
174 })
175 })
176
177 Convey("makeBasePath", func() {
178 cases := []struct{ base, relative, result string }{
179 {"/", "", "/"},
180 {"", "", "/"},
181 {"/foo/", "bar/", "/foo/bar/"},
182 {"/foo/", "bar//", "/foo/bar/"},
183 {"/foo/", "bar", "/foo/bar/"},
184 {"/foo", "//bar", "/foo/bar/"},
185 {"/foo//", "//bar///baz/qux", "/foo/bar/baz/qux/ "},
186 }
187 for _, c := range cases {
188 So(makeBasePath(c.base, c.relative), ShouldEqual , c.result)
189 }
190 })
191
192 Convey("StatusCode() and Written()", func() {
193 ts := httptest.NewServer(r)
194 client := &http.Client{}
195
196 Convey("Should change after calls to Write", func(g C) {
197 a := func(c *Context, next Handler) {
198 g.So(c.Written(), ShouldBeFalse)
199 g.So(c.StatusCode(), ShouldEqual, 0)
200 next(c)
201 g.So(c.Written(), ShouldBeTrue)
202 g.So(c.StatusCode(), ShouldEqual, http.S tatusOK)
203 }
204 b := func(c *Context, next Handler) {
205 g.So(c.Written(), ShouldBeFalse)
206 g.So(c.StatusCode(), ShouldEqual, 0)
207 io.WriteString(c, "foo")
208 g.So(c.Written(), ShouldBeTrue)
209 g.So(c.StatusCode(), ShouldEqual, http.S tatusOK)
210 next(c)
211 g.So(c.Written(), ShouldBeTrue)
212 g.So(c.StatusCode(), ShouldEqual, http.S tatusOK)
213 }
214 c := func(c *Context, next Handler) {
215 g.So(c.Written(), ShouldBeTrue)
216 g.So(c.StatusCode(), ShouldEqual, http.S tatusOK)
217 next(c)
218 g.So(c.Written(), ShouldBeTrue)
219 g.So(c.StatusCode(), ShouldEqual, http.S tatusOK)
220 }
221 handler := func(c *Context) {
222 g.So(c.Written(), ShouldBeTrue)
223 g.So(c.StatusCode(), ShouldEqual, http.S tatusOK)
224 }
225 r.Use(MiddlewareChain{a, b, c})
226 r.GET("/test/write", nil, handler)
227 res, err := client.Get(ts.URL + "/test/write")
228 g.So(err, ShouldBeNil)
229 res.Body.Close()
230 })
231
232 Convey("Should change after calls to WriteHeader", func( g C) {
233 a := func(c *Context, next Handler) {
234 g.So(c.Written(), ShouldBeFalse)
235 g.So(c.StatusCode(), ShouldEqual, 0)
236 next(c)
237 g.So(c.Written(), ShouldBeTrue)
238 g.So(c.StatusCode(), ShouldEqual, http.S tatusTeapot)
239 }
240 b := func(c *Context, next Handler) {
241 g.So(c.Written(), ShouldBeFalse)
242 g.So(c.StatusCode(), ShouldEqual, 0)
243 c.WriteHeader(http.StatusTeapot)
244 g.So(c.Written(), ShouldBeTrue)
245 g.So(c.StatusCode(), ShouldEqual, http.S tatusTeapot)
246 next(c)
247 g.So(c.Written(), ShouldBeTrue)
248 g.So(c.StatusCode(), ShouldEqual, http.S tatusTeapot)
249 }
250 c := func(c *Context, next Handler) {
251 g.So(c.Written(), ShouldBeTrue)
252 g.So(c.StatusCode(), ShouldEqual, http.S tatusTeapot)
253 next(c)
254 g.So(c.Written(), ShouldBeTrue)
255 g.So(c.StatusCode(), ShouldEqual, http.S tatusTeapot)
256 }
257 handler := func(c *Context) {
258 g.So(c.Written(), ShouldBeTrue)
259 g.So(c.StatusCode(), ShouldEqual, http.S tatusTeapot)
260 }
261 r.Use(MiddlewareChain{a, b, c})
262 r.GET("/test/writeheader", nil, handler)
263 res, err := client.Get(ts.URL + "/test/writehead er")
264 g.So(err, ShouldBeNil)
265 res.Body.Close()
266 })
267
268 Reset(func() {
269 ts.Close()
270 })
271 })
272 })
273 }
OLDNEW
« no previous file with comments | « server/router/router.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698