Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1667)

Unified Diff: server/router/router_test.go

Issue 2043423004: Make HTTP middleware easier to use (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: gaemiddleware: add middleware func for WithProd Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « server/router/router.go ('k') | server/settings/admin/handlers.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: server/router/router_test.go
diff --git a/server/router/router_test.go b/server/router/router_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ffb3f89daa89add5392c40d74b0c7caf6933569f
--- /dev/null
+++ b/server/router/router_test.go
@@ -0,0 +1,217 @@
+// Copyright 2016 The LUCI Authors. All rights reserved.
+// Use of this source code is governed under the Apache License, Version 2.0
+// that can be found in the LICENSE file.
+
+package router
+
+import (
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+
+ "golang.org/x/net/context"
+
+ . "github.com/smartystreets/goconvey/convey"
+)
+
+func TestRouter(t *testing.T) {
+ t.Parallel()
+
+ outputKey := "output"
+ client := &http.Client{}
+ appendValue := func(c context.Context, key string, val string) context.Context {
+ var current []string
+ if v := c.Value(key); v != nil {
+ current = v.([]string)
+ }
+ return context.WithValue(c, key, append(current, val))
+ }
+ a := func(c *Context, next Handler) {
+ c.Context = appendValue(c.Context, outputKey, "a:before")
+ next(c)
+ c.Context = appendValue(c.Context, outputKey, "a:after")
+ }
+ b := func(c *Context, next Handler) {
+ c.Context = appendValue(c.Context, outputKey, "b:before")
+ next(c)
+ c.Context = appendValue(c.Context, outputKey, "b:after")
+ }
+ c := func(c *Context, next Handler) {
+ c.Context = appendValue(c.Context, outputKey, "c")
+ next(c)
+ }
+ d := func(c *Context, next Handler) {
+ next(c)
+ c.Context = appendValue(c.Context, outputKey, "d")
+ }
+ stop := func(_ *Context, _ Handler) {}
+ handler := func(c *Context) {
+ c.Context = appendValue(c.Context, outputKey, "handler")
+ }
+
+ Convey("Router", t, func() {
+ r := New()
+
+ Convey("New", func() {
+ Convey("Should initialize non-nil httprouter.Router", func() {
+ So(r.hrouter, ShouldNotBeNil)
+ })
+ })
+
+ Convey("Use", func() {
+ Convey("Should append middleware", func() {
+ So(len(r.middleware), ShouldEqual, 0)
+ r.Use(MiddlewareChain{a, b})
+ So(len(r.middleware), ShouldEqual, 2)
+ })
+ })
+
+ Convey("Subrouter", func() {
+ Convey("Should create new router with values from original router", func() {
+ r.BasePath = "/foo"
+ r.Use(MiddlewareChain{a, b})
+ r2 := r.Subrouter("bar")
+ So(r.hrouter, ShouldPointTo, r2.hrouter)
+ So(r2.BasePath, ShouldEqual, "/foo/bar")
+ So(&r.middleware[0], ShouldNotEqual, &r2.middleware[0])
+ So(&r.middleware[1], ShouldNotEqual, &r2.middleware[1])
+ So(len(r.middleware), ShouldEqual, len(r2.middleware))
+ So(r.middleware[0], ShouldEqual, r2.middleware[0])
+ So(r.middleware[1], ShouldEqual, r2.middleware[1])
+ })
+ })
+
+ Convey("Handle", func() {
+ Convey("Should not modify existing empty r.middleware slice", func() {
+ So(len(r.middleware), ShouldEqual, 0)
+ r.Handle("GET", "/bar", MiddlewareChain{b, c}, handler)
+ So(len(r.middleware), ShouldEqual, 0)
+ })
+
+ Convey("Should not modify existing r.middleware slice", func() {
+ r.Use(MiddlewareChain{a})
+ So(len(r.middleware), ShouldEqual, 1)
+ r.Handle("GET", "/bar", MiddlewareChain{b, c}, handler)
+ So(len(r.middleware), ShouldEqual, 1)
+ })
+ })
+
+ Convey("run", func() {
+ ctx := &Context{Context: context.Background()}
+
+ Convey("Should execute handler when using nil middlewares", func() {
+ run(ctx, nil, nil, handler)
+ So(ctx.Context.Value(outputKey), ShouldResemble, []string{"handler"})
+ })
+
+ Convey("Should execute middlewares and handler in order", func() {
+ m := MiddlewareChain{a, b, c}
+ n := MiddlewareChain{d}
+ run(ctx, m, n, handler)
+ So(ctx.Context.Value(outputKey), ShouldResemble,
+ []string{"a:before", "b:before", "c", "handler", "d", "b:after", "a:after"},
+ )
+ })
+
+ Convey("Should not execute upcoming middleware/handlers if next is not called", func() {
+ mc := MiddlewareChain{a, stop, b}
+ run(ctx, mc, nil, handler)
+ So(ctx.Context.Value(outputKey), ShouldResemble, []string{"a:before", "a:after"})
+ })
+
+ Convey("Should execute next middleware when it encounters nil middleware", func() {
+ Convey("At start of first chain", func() {
+ run(ctx, MiddlewareChain{nil, a}, MiddlewareChain{b}, handler)
+ So(ctx.Context.Value(outputKey), ShouldResemble, []string{"a:before", "b:before", "handler", "b:after", "a:after"})
+ })
+ Convey("At start of second chain", func() {
+ run(ctx, MiddlewareChain{a}, MiddlewareChain{nil, b}, handler)
+ So(ctx.Context.Value(outputKey), ShouldResemble, []string{"a:before", "b:before", "handler", "b:after", "a:after"})
+ })
+ Convey("At end of first chain", func() {
+ run(ctx, MiddlewareChain{a, nil}, MiddlewareChain{b}, handler)
+ So(ctx.Context.Value(outputKey), ShouldResemble, []string{"a:before", "b:before", "handler", "b:after", "a:after"})
+ })
+ Convey("At end of second chain", func() {
+ run(ctx, MiddlewareChain{a}, MiddlewareChain{b, nil}, handler)
+ So(ctx.Context.Value(outputKey), ShouldResemble, []string{"a:before", "b:before", "handler", "b:after", "a:after"})
+ })
+ })
+ })
+
+ Convey("ServeHTTP", func() {
+ ts := httptest.NewServer(r)
+ a := func(c *Context, next Handler) {
+ c.Context = appendValue(c.Context, outputKey, "a:before")
+ next(c)
+ c.Context = appendValue(c.Context, outputKey, "a:after")
+ io.WriteString(c.Writer, strings.Join(c.Context.Value(outputKey).([]string), ","))
+ }
+
+ Convey("Should execute middleware registered in Use and Handle in order", func() {
+ r.Use(MiddlewareChain{a})
+ r.GET("/ab", MiddlewareChain{b}, handler)
+ res, err := client.Get(ts.URL + "/ab")
+ So(err, ShouldBeNil)
+ defer res.Body.Close()
+ So(res.StatusCode, ShouldEqual, http.StatusOK)
+ p, err := ioutil.ReadAll(res.Body)
+ So(err, ShouldBeNil)
+ So(string(p), ShouldEqual, strings.Join(
+ []string{"a:before", "b:before", "handler", "b:after", "a:after"},
+ ",",
+ ))
+ })
+
+ Convey("Should return method not allowed for existing path but wrong method in request", func() {
+ r.POST("/comment", nil, handler)
+ res, err := client.Get(ts.URL + "/comment")
+ So(err, ShouldBeNil)
+ defer res.Body.Close()
+ So(res.StatusCode, ShouldEqual, http.StatusMethodNotAllowed)
+ })
+
+ Convey("Should return expected response from handler", func() {
+ handler := func(c *Context) {
+ c.Writer.Write([]byte("Hello, " + c.Params[0].Value))
+ }
+ r.GET("/hello/:name", MiddlewareChain{c, d}, handler)
+ res, err := client.Get(ts.URL + "/hello/世界")
+ So(err, ShouldBeNil)
+ defer res.Body.Close()
+ So(res.StatusCode, ShouldEqual, http.StatusOK)
+ p, err := ioutil.ReadAll(res.Body)
+ So(err, ShouldBeNil)
+ So(string(p), ShouldEqual, "Hello, 世界")
+ })
+
+ Reset(func() {
+ ts.Close()
+ })
+ })
+
+ Convey("makeBasePath", func() {
+ cases := []struct{ base, relative, result string }{
+ {"/", "", "/"},
+ {"", "", "/"},
+ {"foo", "", "/foo"},
+ {"foo/", "", "/foo/"},
+ {"foo", "/", "/foo/"},
+ {"foo", "bar", "/foo/bar"},
+ {"foo/", "bar", "/foo/bar"},
+ {"foo", "bar/", "/foo/bar/"},
+ {"/foo", "/bar", "/foo/bar"},
+ {"/foo/", "/bar", "/foo/bar"},
+ {"foo//", "///bar", "/foo/bar"},
+ {"foo", "bar///baz/qux", "/foo/bar/baz/qux"},
+ {"//foo//", "///bar///baz/qux/", "/foo/bar/baz/qux/"},
+ }
+ for _, c := range cases {
+ So(makeBasePath(c.base, c.relative), ShouldEqual, c.result)
+ }
+ })
+ })
+}
« no previous file with comments | « server/router/router.go ('k') | server/settings/admin/handlers.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698