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