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

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: Do not allocate merged array in Handle 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 TestGroup(t *testing.T) {
42 t.Parallel()
43 a := func(_ *Context, _ Handler) {}
44 b := func(_ *Context, _ Handler) {}
45
46 Convey("Group derives from original router", t, func() {
47 r1 := New()
48 r1.Use(MiddlewareChain{a, b})
49 r2 := r1.Group("/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() {
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")
83 next(c)
84 io.WriteString(c, "7")
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)
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 mc.Run(&Context{writer: rec}, handler)
124 So(rec.Body.String(), ShouldResemble, "17")
125 })
126 }
127
128 func TestMergeMiddlewareChains(t *testing.T) {
129 t.Parallel()
130 a := func(_ *Context, _ Handler) {}
131 b := func(_ *Context, _ Handler) {}
132 c := func(_ *Context, _ Handler) {}
133 d := func(_ *Context, _ Handler) {}
134
135 Convey("Merged length is sum of lengths", t, func() {
136 mc1 := MiddlewareChain{a, b}
137 mc2 := MiddlewareChain{c}
138 merged := MergeMiddlewareChains(mc1, mc2)
139 So(len(merged), ShouldEqual, 3)
140 })
141
142 Convey("Merged slice points to separate array", t, func() {
143 mc1 := MiddlewareChain{a, b}
144 mc2 := MiddlewareChain{c, d}
145 merged := MergeMiddlewareChains(mc1, mc2)
146 So(&merged[0], ShouldNotPointTo, &mc1[0])
147 })
148
149 Convey("Functions in merged slice are same", t, func() {
150 mc1 := MiddlewareChain{a, b}
151 mc2 := MiddlewareChain{c, d}
152 merged := MergeMiddlewareChains(mc1, mc2)
153 So(merged[0], ShouldEqual, mc1[0])
154 So(merged[1], ShouldEqual, mc1[1])
155 So(merged[2], ShouldEqual, mc2[0])
156 So(merged[3], ShouldEqual, mc2[1])
157 })
158 }
159
160 func TestServeHTTP(t *testing.T) {
161 t.Parallel()
162 setup := func(h http.Handler) (client *http.Client, ts *httptest.Server) {
163 client = &http.Client{}
164 client.Timeout = 10 * time.Second
165 ts = httptest.NewServer(h)
166 return
167 }
168 cleanup := func(ts *httptest.Server) {
169 ts.Close()
170 }
171 a := func(c *Context, next Handler) {
172 c.Context = context.WithValue(c.Context, "a", "A")
173 next(c)
174 }
175 b := func(c *Context, next Handler) {
176 val := c.Value("a").(string)
177 assert.ShouldEqual(val, "A")
178 c.Context = context.WithValue(c.Context, "a", val+"B")
179 next(c)
180 }
181 handler := func(c *Context) {
182 assert.ShouldEqual(c.Value("b"), "AB")
183 c.WriteHeader(http.StatusOK)
184 }
185 helloHandler := func(c *Context) {
186 c.Write([]byte("Hello, " + c.Params[0].Value))
187 }
188
189 Convey("Middleware registered using Use and Handle should both execute i n order", t, func() {
190 r := New()
191 r.Use(MiddlewareChain{a})
192 r.GET("/foo", MiddlewareChain{b}, handler)
193 client, ts := setup(r)
194 defer cleanup(ts)
195
196 res, err := client.Get(ts.URL + "/foo")
197 So(err, ShouldBeNil)
198 res.Body.Close()
199 })
200
201 Convey("Wrong HTTP method for existing path should return method not all owed", t, func() {
202 r := New()
203 r.Use(MiddlewareChain{a})
204 r.GET("/foo", MiddlewareChain{b}, handler)
205 client, ts := setup(r)
206 defer cleanup(ts)
207
208 res, err := client.Post(ts.URL+"/foo", "", nil)
209 So(err, ShouldBeNil)
210 defer res.Body.Close()
211 So(res.StatusCode, ShouldEqual, http.StatusMethodNotAllowed)
212 })
213
214 Convey("Response should match expected value", t, func() {
215 r := New()
216 r.Use(MiddlewareChain{a})
217 r.GET("/hello/:name", MiddlewareChain{b}, helloHandler)
218 client, ts := setup(r)
219 defer cleanup(ts)
220
221 res, err := client.Get(ts.URL + "/hello/世界")
222 So(err, ShouldBeNil)
223 defer res.Body.Close()
224 p, err := ioutil.ReadAll(res.Body)
225 So(res.StatusCode, ShouldEqual, http.StatusOK)
226 So(string(p), ShouldEqual, "Hello, 世界")
227 })
228 }
229
230 func TestWrite(t *testing.T) {
231 t.Parallel()
232 setup := func(h http.Handler) (client *http.Client, ts *httptest.Server) {
233 client = &http.Client{}
234 client.Timeout = 10 * time.Second
235 ts = httptest.NewServer(h)
236 return
237 }
238 cleanup := func(ts *httptest.Server) {
239 ts.Close()
240 }
241
242 Convey("Written() and StatusCode() should change before and after Write" , t, func() {
243 a := func(c *Context, next Handler) {
244 assert.ShouldBeFalse(c.Written())
245 assert.ShouldEqual(c.StatusCode(), 0)
246 next(c)
247 assert.ShouldBeTrue(c.Written())
248 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
249 }
250 b := func(c *Context, next Handler) {
251 assert.ShouldBeFalse(c.Written())
252 assert.ShouldEqual(c.StatusCode(), 0)
253 io.WriteString(c, "foo")
254 assert.ShouldBeTrue(c.Written())
255 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
256 next(c)
257 assert.ShouldBeTrue(c.Written())
258 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
259 }
260 c := func(c *Context, next Handler) {
261 assert.ShouldBeTrue(c.Written())
262 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
263 next(c)
264 assert.ShouldBeTrue(c.Written())
265 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
266 }
267 handler := func(c *Context) {
268 assert.ShouldBeTrue(c.Written())
269 assert.ShouldEqual(c.StatusCode(), http.StatusOK)
270 }
271
272 r := New()
273 r.Use(MiddlewareChain{a, b, c})
274 r.GET("/test/write", nil, handler)
275 client, ts := setup(r)
276 defer cleanup(ts)
277
278 res, err := client.Get(ts.URL + "/test/write")
279 So(err, ShouldBeNil)
280 res.Body.Close()
281 })
282
283 Convey("Written() and StatusCode() should change before and after WriteH eader", t, func() {
284 a := func(c *Context, next Handler) {
285 assert.ShouldBeFalse(c.Written())
286 assert.ShouldEqual(c.StatusCode(), 0)
287 next(c)
288 assert.ShouldBeTrue(c.Written())
289 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
290 }
291 b := func(c *Context, next Handler) {
292 assert.ShouldBeFalse(c.Written())
293 assert.ShouldEqual(c.StatusCode(), 0)
294 c.WriteHeader(http.StatusTeapot)
295 assert.ShouldBeTrue(c.Written())
296 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
297 next(c)
298 assert.ShouldBeTrue(c.Written())
299 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
300 }
301 c := func(c *Context, next Handler) {
302 assert.ShouldBeTrue(c.Written())
303 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
304 next(c)
305 assert.ShouldBeTrue(c.Written())
306 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
307 }
308 handler := func(c *Context) {
309 assert.ShouldBeTrue(c.Written())
310 assert.ShouldEqual(c.StatusCode(), http.StatusTeapot)
311 }
312
313 r := New()
314 r.Use(MiddlewareChain{a, b, c})
315 r.GET("/test/writeheader", nil, handler)
316 client, ts := setup(r)
317 defer cleanup(ts)
318
319 res, err := client.Get(ts.URL + "/test/writeheader")
320 So(err, ShouldBeNil)
321 res.Body.Close()
322 })
323 }
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