| 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, outputKey, "a:before") |
| 34 next(c) |
| 35 c.Context = appendValue(c, outputKey, "a:after") |
| 36 } |
| 37 b := func(c *Context, next Handler) { |
| 38 c.Context = appendValue(c, outputKey, "b:before") |
| 39 next(c) |
| 40 c.Context = appendValue(c, outputKey, "b:after") |
| 41 } |
| 42 c := func(c *Context, next Handler) { |
| 43 c.Context = appendValue(c, outputKey, "c") |
| 44 next(c) |
| 45 } |
| 46 d := func(c *Context, next Handler) { |
| 47 next(c) |
| 48 c.Context = appendValue(c, outputKey, "d") |
| 49 } |
| 50 stop := func(_ *Context, _ Handler) {} |
| 51 handler := func(c *Context) { |
| 52 c.Context = appendValue(c, 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.Value(outputKey), ShouldResemble, []strin
g{"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.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.Value(outputKey), ShouldResemble, []strin
g{"a:before", "a:after"}) |
| 123 }) |
| 124 }) |
| 125 |
| 126 Convey("ServeHTTP", func() { |
| 127 ts := httptest.NewServer(r) |
| 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 } |
| OLD | NEW |