Skip to content

Commit

Permalink
http: test Chain in middleware_test.go
Browse files Browse the repository at this point in the history
  • Loading branch information
ldb committed Jun 7, 2018
1 parent 1d01877 commit d9bbc83
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 5 deletions.
6 changes: 2 additions & 4 deletions http/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@ import (
"net/http"
)

type Middlware func(handler http.Handler) http.Handler

// Chain takes a final http.Handler and a list of Middlewares and builds a call chain such that
// an incoming request passes all Middlwares in the order they were appended and finally reaches final.
func Chain(final http.Handler, m ...Middlware) http.Handler {
func Chain(final http.Handler, m ...func(handler http.Handler) http.Handler) http.Handler {
for i := len(m) - 1; i >= 0; i-- {
final = m[i](final)
}
return final
}

func NewAuthMiddleware(provider eduboard.UserAuthenticationProvider) Middlware {
func NewAuthMiddleware(provider eduboard.UserAuthenticationProvider) func(handler http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("sessionID")
Expand Down
29 changes: 28 additions & 1 deletion http/middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,38 @@ import (
"errors"
"github.com/eduboard/backend/mock"
"github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)

func TestChain(t *testing.T) {
var final, oneCalled, twoCalled, threeCalled = &mock.Check{}, &mock.Check{}, &mock.Check{}, &mock.Check{}
finalHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.True(t, oneCalled.Passed, "first wrapped function not called")
assert.True(t, twoCalled.Passed, "second wrapped function not called")
assert.True(t, threeCalled.Passed, "third wrapped function not called")
final.Passed = true
n, err := w.Write([]byte("ok"))
assert.Equal(t, 2, n)
assert.Nil(t, err)
})

handlers := mock.GenerateCheckedMiddlewares(oneCalled, twoCalled, threeCalled)
c := Chain(finalHandler, handlers...)
req := httptest.NewRequest("", "/", nil)
rr := httptest.NewRecorder()
c.ServeHTTP(rr, req)

res := rr.Result()
defer res.Body.Close()
resBody, _ := ioutil.ReadAll(res.Body)

assert.True(t, final.Passed, "inner wrapped function not called")
assert.Equal(t, "ok", string(resBody), "response not correct")
}

func TestAppServer_NewAuthMiddleware(t *testing.T) {
var as = &mock.UserAuthenticationProvider{
CheckAuthenticationFn: func(sessionID string) (err error, ok bool) {
Expand Down Expand Up @@ -61,4 +88,4 @@ func TestAppServer_NewAuthMiddleware(t *testing.T) {
assert.True(t, as.CheckAuthenticationFnInvoked, "authentication was not actually checked")
})
}
}
}
22 changes: 22 additions & 0 deletions mock/middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package mock

import "net/http"

type Check struct {
Passed bool
}

func GenerateCheckedMiddlewares(checks ...*Check) []func(http.Handler) http.Handler {
var handlers = make([]func(http.Handler) http.Handler, len(checks))
for k, c := range checks {
func(c *Check) { // Wrapping the function call like this creates a closure, making sure `c` does not change before evaluation.
handlers[k] = func(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c.Passed = true
handler.ServeHTTP(w, r)
})
}
}(c)
}
return handlers
}

0 comments on commit d9bbc83

Please sign in to comment.