| 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 client := &http.Client{} |
| 25 appendValue := func(c context.Context, key string, val string) context.C
ontext { |
| 26 var current []string |
| 27 if v := c.Value(key); v != nil { |
| 28 current = v.([]string) |
| 29 } |
| 30 return context.WithValue(c, key, append(current, val)) |
| 31 } |
| 32 a := func(c *Context, next Handler) { |
| 33 c.Context = appendValue(c.Context, outputKey, "a:before") |
| 34 next(c) |
| 35 c.Context = appendValue(c.Context, outputKey, "a:after") |
| 36 } |
| 37 b := func(c *Context, next Handler) { |
| 38 c.Context = appendValue(c.Context, outputKey, "b:before") |
| 39 next(c) |
| 40 c.Context = appendValue(c.Context, outputKey, "b:after") |
| 41 } |
| 42 c := func(c *Context, next Handler) { |
| 43 c.Context = appendValue(c.Context, outputKey, "c") |
| 44 next(c) |
| 45 } |
| 46 d := func(c *Context, next Handler) { |
| 47 next(c) |
| 48 c.Context = appendValue(c.Context, outputKey, "d") |
| 49 } |
| 50 stop := func(_ *Context, _ Handler) {} |
| 51 handler := func(c *Context) { |
| 52 c.Context = appendValue(c.Context, outputKey, "handler") |
| 53 } |
| 54 |
| 55 Convey("Router", t, func() { |
| 56 r := New() |
| 57 |
| 58 Convey("New", func() { |
| 59 Convey("Should initialize non-nil httprouter.Router", fu
nc() { |
| 60 So(r.hrouter, ShouldNotBeNil) |
| 61 }) |
| 62 }) |
| 63 |
| 64 Convey("Use", func() { |
| 65 Convey("Should append middleware", func() { |
| 66 So(len(r.middleware), ShouldEqual, 0) |
| 67 r.Use(MiddlewareChain{a, b}) |
| 68 So(len(r.middleware), ShouldEqual, 2) |
| 69 }) |
| 70 }) |
| 71 |
| 72 Convey("Subrouter", func() { |
| 73 Convey("Should create new router with values from origin
al router", func() { |
| 74 r.BasePath = "/foo" |
| 75 r.Use(MiddlewareChain{a, b}) |
| 76 r2 := r.Subrouter("bar") |
| 77 So(r.hrouter, ShouldPointTo, r2.hrouter) |
| 78 So(r2.BasePath, ShouldEqual, "/foo/bar") |
| 79 So(&r.middleware[0], ShouldNotEqual, &r2.middlew
are[0]) |
| 80 So(&r.middleware[1], ShouldNotEqual, &r2.middlew
are[1]) |
| 81 So(len(r.middleware), ShouldEqual, len(r2.middle
ware)) |
| 82 So(r.middleware[0], ShouldEqual, r2.middleware[0
]) |
| 83 So(r.middleware[1], ShouldEqual, r2.middleware[1
]) |
| 84 }) |
| 85 }) |
| 86 |
| 87 Convey("Handle", func() { |
| 88 Convey("Should not modify existing empty r.middleware sl
ice", func() { |
| 89 So(len(r.middleware), ShouldEqual, 0) |
| 90 r.Handle("GET", "/bar", MiddlewareChain{b, c}, h
andler) |
| 91 So(len(r.middleware), ShouldEqual, 0) |
| 92 }) |
| 93 |
| 94 Convey("Should not modify existing r.middleware slice",
func() { |
| 95 r.Use(MiddlewareChain{a}) |
| 96 So(len(r.middleware), ShouldEqual, 1) |
| 97 r.Handle("GET", "/bar", MiddlewareChain{b, c}, h
andler) |
| 98 So(len(r.middleware), ShouldEqual, 1) |
| 99 }) |
| 100 }) |
| 101 |
| 102 Convey("run", func() { |
| 103 ctx := &Context{Context: context.Background()} |
| 104 |
| 105 Convey("Should execute handler when using nil middleware
s", func() { |
| 106 run(ctx, nil, nil, handler) |
| 107 So(ctx.Context.Value(outputKey), ShouldResemble,
[]string{"handler"}) |
| 108 }) |
| 109 |
| 110 Convey("Should execute middlewares and handler in order"
, func() { |
| 111 m := MiddlewareChain{a, b, c} |
| 112 n := MiddlewareChain{d} |
| 113 run(ctx, m, n, handler) |
| 114 So(ctx.Context.Value(outputKey), ShouldResemble, |
| 115 []string{"a:before", "b:before", "c", "h
andler", "d", "b:after", "a:after"}, |
| 116 ) |
| 117 }) |
| 118 |
| 119 Convey("Should not execute upcoming middleware/handlers
if next is not called", func() { |
| 120 mc := MiddlewareChain{a, stop, b} |
| 121 run(ctx, mc, nil, handler) |
| 122 So(ctx.Context.Value(outputKey), ShouldResemble,
[]string{"a:before", "a:after"}) |
| 123 }) |
| 124 |
| 125 Convey("Should execute next middleware when it encounter
s nil middleware", func() { |
| 126 Convey("At start of first chain", func() { |
| 127 run(ctx, MiddlewareChain{nil, a}, Middle
wareChain{b}, handler) |
| 128 So(ctx.Context.Value(outputKey), ShouldR
esemble, []string{"a:before", "b:before", "handler", "b:after", "a:after"}) |
| 129 }) |
| 130 Convey("At start of second chain", func() { |
| 131 run(ctx, MiddlewareChain{a}, MiddlewareC
hain{nil, b}, handler) |
| 132 So(ctx.Context.Value(outputKey), ShouldR
esemble, []string{"a:before", "b:before", "handler", "b:after", "a:after"}) |
| 133 }) |
| 134 Convey("At end of first chain", func() { |
| 135 run(ctx, MiddlewareChain{a, nil}, Middle
wareChain{b}, handler) |
| 136 So(ctx.Context.Value(outputKey), ShouldR
esemble, []string{"a:before", "b:before", "handler", "b:after", "a:after"}) |
| 137 }) |
| 138 Convey("At end of second chain", func() { |
| 139 run(ctx, MiddlewareChain{a}, MiddlewareC
hain{b, nil}, handler) |
| 140 So(ctx.Context.Value(outputKey), ShouldR
esemble, []string{"a:before", "b:before", "handler", "b:after", "a:after"}) |
| 141 }) |
| 142 }) |
| 143 }) |
| 144 |
| 145 Convey("ServeHTTP", func() { |
| 146 ts := httptest.NewServer(r) |
| 147 a := func(c *Context, next Handler) { |
| 148 c.Context = appendValue(c.Context, outputKey, "a
:before") |
| 149 next(c) |
| 150 c.Context = appendValue(c.Context, outputKey, "a
:after") |
| 151 io.WriteString(c.Writer, strings.Join(c.Context.
Value(outputKey).([]string), ",")) |
| 152 } |
| 153 |
| 154 Convey("Should execute middleware registered in Use and
Handle in order", func() { |
| 155 r.Use(MiddlewareChain{a}) |
| 156 r.GET("/ab", MiddlewareChain{b}, handler) |
| 157 res, err := client.Get(ts.URL + "/ab") |
| 158 So(err, ShouldBeNil) |
| 159 defer res.Body.Close() |
| 160 So(res.StatusCode, ShouldEqual, http.StatusOK) |
| 161 p, err := ioutil.ReadAll(res.Body) |
| 162 So(err, ShouldBeNil) |
| 163 So(string(p), ShouldEqual, strings.Join( |
| 164 []string{"a:before", "b:before", "handle
r", "b:after", "a:after"}, |
| 165 ",", |
| 166 )) |
| 167 }) |
| 168 |
| 169 Convey("Should return method not allowed for existing pa
th but wrong method in request", func() { |
| 170 r.POST("/comment", nil, handler) |
| 171 res, err := client.Get(ts.URL + "/comment") |
| 172 So(err, ShouldBeNil) |
| 173 defer res.Body.Close() |
| 174 So(res.StatusCode, ShouldEqual, http.StatusMetho
dNotAllowed) |
| 175 }) |
| 176 |
| 177 Convey("Should return expected response from handler", f
unc() { |
| 178 handler := func(c *Context) { |
| 179 c.Writer.Write([]byte("Hello, " + c.Para
ms[0].Value)) |
| 180 } |
| 181 r.GET("/hello/:name", MiddlewareChain{c, d}, han
dler) |
| 182 res, err := client.Get(ts.URL + "/hello/世界") |
| 183 So(err, ShouldBeNil) |
| 184 defer res.Body.Close() |
| 185 So(res.StatusCode, ShouldEqual, http.StatusOK) |
| 186 p, err := ioutil.ReadAll(res.Body) |
| 187 So(err, ShouldBeNil) |
| 188 So(string(p), ShouldEqual, "Hello, 世界") |
| 189 }) |
| 190 |
| 191 Reset(func() { |
| 192 ts.Close() |
| 193 }) |
| 194 }) |
| 195 |
| 196 Convey("makeBasePath", func() { |
| 197 cases := []struct{ base, relative, result string }{ |
| 198 {"/", "", "/"}, |
| 199 {"", "", "/"}, |
| 200 {"foo", "", "/foo"}, |
| 201 {"foo/", "", "/foo/"}, |
| 202 {"foo", "/", "/foo/"}, |
| 203 {"foo", "bar", "/foo/bar"}, |
| 204 {"foo/", "bar", "/foo/bar"}, |
| 205 {"foo", "bar/", "/foo/bar/"}, |
| 206 {"/foo", "/bar", "/foo/bar"}, |
| 207 {"/foo/", "/bar", "/foo/bar"}, |
| 208 {"foo//", "///bar", "/foo/bar"}, |
| 209 {"foo", "bar///baz/qux", "/foo/bar/baz/qux"}, |
| 210 {"//foo//", "///bar///baz/qux/", "/foo/bar/baz/q
ux/"}, |
| 211 } |
| 212 for _, c := range cases { |
| 213 So(makeBasePath(c.base, c.relative), ShouldEqual
, c.result) |
| 214 } |
| 215 }) |
| 216 }) |
| 217 } |
| OLD | NEW |