mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 18:30:41 -06:00
534ece064b
* pkg/web: closure-style middlewares Switches the middleware execution model from web.Handlers in a slice to web.Middleware. Middlewares are temporarily kept in a slice to preserve ordering, but prior to execution they are applied, forming a giant call-stack, giving granular control over the execution flow. * pkg/middleware: adapt to web.Middleware * pkg/middleware/recovery: use c.Req over req c.Req gets updated by future handlers, while req stays static. The current recovery implementation needs this newer information * pkg/web: correct middleware ordering * pkg/webtest: adapt middleware * pkg/web/hack: set w and r onto web.Context By adopting std middlewares, it may happen they invoke next(w,r) without putting their modified w,r into the web.Context, leading old-style handlers to operate on outdated fields. pkg/web now takes care of this * pkg/middleware: selectively use future context * pkg/web: accept closure-style on Use() * webtest: Middleware testing adds a utility function to web/webtest to obtain a http.ResponseWriter, http.Request and http.Handler the same as a middleware that runs would receive * *: cleanup * pkg/web: don't wrap Middleware from Router * pkg/web: require chain to write response * *: remove temp files * webtest: don't require chain write * *: cleanup
74 lines
1.9 KiB
Go
74 lines
1.9 KiB
Go
package webtest
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
|
|
"github.com/grafana/grafana/pkg/web"
|
|
)
|
|
|
|
type Context struct {
|
|
Req *http.Request
|
|
Rw http.ResponseWriter
|
|
Next http.Handler
|
|
}
|
|
|
|
// Middleware is a utility for testing middlewares
|
|
type Middleware struct {
|
|
// Before are run ahead of the returned context
|
|
Before []web.Handler
|
|
// After are part of the http.Handler chain
|
|
After []web.Handler
|
|
// The actual handler at the end of the chain
|
|
Handler web.Handler
|
|
}
|
|
|
|
// MiddlewareContext returns a *http.Request, http.ResponseWriter and http.Handler
|
|
// exactly as if it was passed to a middleware
|
|
func MiddlewareContext(test Middleware, req *http.Request) *Context {
|
|
m := web.New()
|
|
|
|
// pkg/web requires the chain to write an HTTP response.
|
|
// While this ensures a basic amount of correctness for real handler chains,
|
|
// it is naturally incompatible with this package, as we terminate the chain early to pass its
|
|
// state to the surrounding test.
|
|
// By replacing the http.ResponseWriter and writing to the old one we make pkg/web happy.
|
|
m.Use(func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
rw := web.Rw(httptest.NewRecorder(), r)
|
|
next.ServeHTTP(rw, r)
|
|
})
|
|
})
|
|
|
|
for _, mw := range test.Before {
|
|
m.Use(mw)
|
|
}
|
|
|
|
ch := make(chan *Context)
|
|
m.Use(func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ch <- &Context{
|
|
Req: r,
|
|
Rw: w,
|
|
Next: next,
|
|
}
|
|
})
|
|
})
|
|
|
|
for _, mw := range test.After {
|
|
m.Use(mw)
|
|
}
|
|
|
|
// set the provided (or noop) handler to exactly the queried path
|
|
handler := test.Handler
|
|
if handler == nil {
|
|
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
|
}
|
|
m.Handle(req.Method, req.URL.RequestURI(), []web.Handler{handler})
|
|
go m.ServeHTTP(httptest.NewRecorder(), req)
|
|
|
|
return <-ch
|
|
}
|