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

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 documentation style 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
« server/router/router.go ('K') | « 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 "testing"
13 "time"
14
15 "golang.org/x/net/context"
16
17 assert "github.com/smartystreets/assertions"
18 . "github.com/smartystreets/goconvey/convey"
19 )
20
21 func TestNew(t *testing.T) {
22 t.Parallel()
23 Convey("Initializes non-nil httprouter.Router", t, func() {
24 So(New().hrouter, ShouldNotBeNil)
25 })
26 }
27
28 func TestUse(t *testing.T) {
29 t.Parallel()
30 a := func(_ *Context, _ Handler) {}
31 b := func(_ *Context, _ Handler) {}
32
33 Convey("Use appends middleware", t, func() {
34 r := New()
35 So(len(r.middleware), ShouldEqual, 0)
36 r.Use(MiddlewareChain{a, b})
37 So(len(r.middleware), ShouldEqual, 2)
38 })
39 }
40
41 func TestSubrouter(t *testing.T) {
42 t.Parallel()
43 a := func(_ *Context, _ Handler) {}
44 b := func(_ *Context, _ Handler) {}
nodir 2016/06/16 04:20:25 I don't know if you do it intentionally or not, bu
nishanths 2016/06/16 22:11:26 Thanks. Rewritten.
45
46 Convey("Subrouter derives from original router", t, func() {
47 r1 := New()
48 r1.Use(MiddlewareChain{a, b})
49 r2 := r1.Subrouter("/foo")
50 So(r1.hrouter, ShouldPointTo, r2.hrouter)
51 So(&r1.middleware[0], ShouldNotPointTo, &r2.middleware[0])
52 So(len(r1.middleware), ShouldEqual, len(r2.middleware))
53 })
54 }
55
56 func TestHandle(t *testing.T) {
57 t.Parallel()
58 a := func(_ *Context, _ Handler) {}
59 b := func(_ *Context, _ Handler) {}
60 c := func(_ *Context, _ Handler) {}
61 handler := func(_ *Context) {}
62
63 Convey("No side-effects on r.middleware", t, func() {
64 r := New()
65 So(len(r.middleware), ShouldEqual, 0)
66 r.Handle("GET", "/bar", MiddlewareChain{b, c}, handler)
67 So(len(r.middleware), ShouldEqual, 0)
68 })
69
70 Convey("No side-effects on r.middleware", t, func() {
nodir 2016/06/16 04:20:25 convey usually panics on identical names. make the
nishanths 2016/06/16 22:11:26 Thanks for the tip. Done.
71 r := New()
72 r.Use(MiddlewareChain{a})
73 So(len(r.middleware), ShouldEqual, 1)
74 r.Handle("GET", "/bar", MiddlewareChain{b, c}, handler)
75 So(len(r.middleware), ShouldEqual, 1)
76 })
77 }
78
79 func TestRunMiddlewareChain(t *testing.T) {
80 t.Parallel()
81 a := func(c *Context, next Handler) {
82 io.WriteString(c, "1")
nodir 2016/06/16 04:20:25 consider replacing digits with something that indi
nishanths 2016/06/16 22:11:26 Done.
83 next(c)
84 io.WriteString(c, "7")
nodir 2016/06/16 04:20:25 hm.. this test violates middleware rule that it sh
nishanths 2016/06/16 22:11:26 Done, using context.Context instead.
85 }
86 b := func(c *Context, next Handler) {
87 io.WriteString(c, "2")
88 next(c)
89 io.WriteString(c, "6")
90 }
91 c := func(c *Context, next Handler) {
92 io.WriteString(c, "3")
93 next(c)
94 }
95 d := func(c *Context, next Handler) {
96 next(c)
97 io.WriteString(c, "5")
98 }
99 stop := func(_ *Context, _ Handler) {}
100 handler := func(c *Context) {
101 io.WriteString(c, "4")
102 }
103
104 Convey("Handles length 0 chains", t, func() {
105 rec := httptest.NewRecorder()
106 var m MiddlewareChain
107 n := MiddlewareChain{}
108 run(&Context{writer: rec}, m, n, handler)
nodir 2016/06/16 04:20:25 you could just pass nils instead as middleware cha
nishanths 2016/06/16 22:11:26 Done. For some reason, I was thinking we would nee
109 So(rec.Body.String(), ShouldResemble, "4")
110 })
111
112 Convey("Executes in order", t, func() {
113 rec := httptest.NewRecorder()
114 m := MiddlewareChain{a, b, c}
115 n := MiddlewareChain{d}
116 run(&Context{writer: rec}, m, n, handler)
117 So(rec.Body.String(), ShouldResemble, "1234567")
118 })
119
120 Convey("Not calling next does not execute upcoming handlers", t, func() {
121 rec := httptest.NewRecorder()
122 mc := MiddlewareChain{a, stop, b}
123 run(&Context{writer: rec}, mc, nil, handler)
124 So(rec.Body.String(), ShouldResemble, "17")
125 })
126 }
127
128 func TestServeHTTP(t *testing.T) {
129 t.Parallel()
130 setup := func(h http.Handler) (client *http.Client, ts *httptest.Server) {
131 client = &http.Client{}
132 client.Timeout = 10 * time.Second
133 ts = httptest.NewServer(h)
134 return
135 }
136 cleanup := func(ts *httptest.Server) {
137 ts.Close()
138 }
nodir 2016/06/16 04:20:25 setup and cleanup can be inlined if you use hierar
nishanths 2016/06/16 22:11:26 Done.
139 a := func(c *Context, next Handler) {
140 c.Context = context.WithValue(c.Context, "a", "A")
141 next(c)
142 }
143 b := func(c *Context, next Handler) {
144 val := c.Value("a").(string)
145 assert.ShouldEqual(val, "A")
146 c.Context = context.WithValue(c.Context, "a", val+"B")
147 next(c)
148 }
149 handler := func(c *Context) {
150 assert.ShouldEqual(c.Value("b"), "AB")
151 c.WriteHeader(http.StatusOK)
152 }
153 helloHandler := func(c *Context) {
154 c.Write([]byte("Hello, " + c.Params[0].Value))
155 }
156
157 Convey("Middleware registered using Use and Handle should both execute i n order", t, func() {
158 r := New()
159 r.Use(MiddlewareChain{a})
160 r.GET("/foo", MiddlewareChain{b}, handler)
161 client, ts := setup(r)
162 defer cleanup(ts)
163
164 res, err := client.Get(ts.URL + "/foo")
165 So(err, ShouldBeNil)
166 res.Body.Close()
167 })
168
169 Convey("Wrong HTTP method for existing path should return method not all owed", t, func() {
170 r := New()
171 r.Use(MiddlewareChain{a})
172 r.GET("/foo", MiddlewareChain{b}, handler)
173 client, ts := setup(r)
174 defer cleanup(ts)
175
176 res, err := client.Post(ts.URL+"/foo", "", nil)
177 So(err, ShouldBeNil)
178 defer res.Body.Close()
179 So(res.StatusCode, ShouldEqual, http.StatusMethodNotAllowed)
180 })
181
182 Convey("Response should match expected value", t, func() {
183 r := New()
184 r.Use(MiddlewareChain{a})
185 r.GET("/hello/:name", MiddlewareChain{b}, helloHandler)
186 client, ts := setup(r)
187 defer cleanup(ts)
188
189 res, err := client.Get(ts.URL + "/hello/世界")
190 So(err, ShouldBeNil)
191 defer res.Body.Close()
192 p, err := ioutil.ReadAll(res.Body)
193 So(res.StatusCode, ShouldEqual, http.StatusOK)
194 So(string(p), ShouldEqual, "Hello, 世界")
195 })
196 }
197
198 func TestMakeBasePath(t *testing.T) {
199 t.Parallel()
200 cases := []struct{ base, relative, result string }{
201 {"/", "", "/"},
202 {"", "", "/"},
203 {"/foo/", "bar/", "/foo/bar/"},
204 {"/foo/", "bar//", "/foo/bar/"},
205 {"/foo/", "bar", "/foo/bar/"},
206 {"/foo", "//bar", "/foo/bar/"},
207 {"/foo//", "//bar///baz/qux", "/foo/bar/baz/qux/"},
208 }
209
210 Convey("Makes cleaned base path with exactly one trailing '/'", t, func( ) {
211 for _, c := range cases {
212 So(makeBasePath(c.base, c.relative), ShouldEqual, c.resu lt)
213 }
214 })
215 }
216
217 func TestWrite(t *testing.T) {
218 t.Parallel()
219 setup := func(h http.Handler) (client *http.Client, ts *httptest.Server) {
220 client = &http.Client{}
221 client.Timeout = 10 * time.Second
222 ts = httptest.NewServer(h)
223 return
224 }
225 cleanup := func(ts *httptest.Server) {
226 ts.Close()
227 }
228
229 Convey("Written() and StatusCode() should change before and after Write" , t, func() {
230 a := func(c *Context, next Handler) {
231 assert.ShouldBeFalse(c.Written())
232 assert.ShouldEqual(c.StatusCode(), 0)
233 next(c)
234 assert.ShouldBeTrue(c.Written())
235 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
236 }
237 b := func(c *Context, next Handler) {
238 assert.ShouldBeFalse(c.Written())
239 assert.ShouldEqual(c.StatusCode(), 0)
240 io.WriteString(c, "foo")
241 assert.ShouldBeTrue(c.Written())
242 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
243 next(c)
244 assert.ShouldBeTrue(c.Written())
245 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
246 }
247 c := func(c *Context, next Handler) {
248 assert.ShouldBeTrue(c.Written())
249 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
250 next(c)
251 assert.ShouldBeTrue(c.Written())
252 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
253 }
254 handler := func(c *Context) {
255 assert.ShouldBeTrue(c.Written())
256 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
257 }
258
259 r := New()
260 r.Use(MiddlewareChain{a, b, c})
261 r.GET("/test/write", nil, handler)
262 client, ts := setup(r)
263 defer cleanup(ts)
264
265 res, err := client.Get(ts.URL + "/test/write")
266 So(err, ShouldBeNil)
267 res.Body.Close()
268 })
269
270 Convey("Written() and StatusCode() should change before and after WriteH eader", t, func() {
271 a := func(c *Context, next Handler) {
272 assert.ShouldBeFalse(c.Written())
nodir 2016/06/16 04:20:25 why not So(c.Written(), ShouldBeFalse) this is m
nishanths 2016/06/16 22:11:26 Done. Earlier I used assertions because the tests
273 assert.ShouldEqual(c.StatusCode(), 0)
274 next(c)
275 assert.ShouldBeTrue(c.Written())
276 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
277 }
278 b := func(c *Context, next Handler) {
279 assert.ShouldBeFalse(c.Written())
280 assert.ShouldEqual(c.StatusCode(), 0)
281 c.WriteHeader(http.StatusTeapot)
282 assert.ShouldBeTrue(c.Written())
283 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
284 next(c)
285 assert.ShouldBeTrue(c.Written())
286 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
287 }
288 c := func(c *Context, next Handler) {
289 assert.ShouldBeTrue(c.Written())
290 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
291 next(c)
292 assert.ShouldBeTrue(c.Written())
293 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
294 }
295 handler := func(c *Context) {
296 assert.ShouldBeTrue(c.Written())
297 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
298 }
299
300 r := New()
301 r.Use(MiddlewareChain{a, b, c})
302 r.GET("/test/writeheader", nil, handler)
303 client, ts := setup(r)
304 defer cleanup(ts)
305
306 res, err := client.Get(ts.URL + "/test/writeheader")
307 So(err, ShouldBeNil)
308 res.Body.Close()
309 })
310 }
OLDNEW
« server/router/router.go ('K') | « server/router/router.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698