Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 } | |
| OLD | NEW |