| 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 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 } |
| OLD | NEW |