grafana/pkg/web/webtest/webtest.go

153 lines
4.1 KiB
Go
Raw Normal View History

package webtest
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/google/uuid"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/web"
)
var requests = map[string]*contextmodel.ReqContext{}
type Server struct {
t testing.TB
Mux *web.Mux
RouteRegister routing.RouteRegister
TestServer *httptest.Server
}
// NewServer starts and returns a new server.
func NewServer(t testing.TB, routeRegister routing.RouteRegister) *Server {
t.Helper()
m := web.New()
initCtx := &contextmodel.ReqContext{}
m.Use(func(c *web.Context) {
initCtx.Context = c
initCtx.Logger = log.New("api-test")
c.Req = c.Req.WithContext(ctxkey.Set(c.Req.Context(), initCtx))
})
m.UseMiddleware(requestContextMiddleware())
routeRegister.Register(m.Router)
testServer := httptest.NewServer(m)
t.Cleanup(testServer.Close)
return &Server{
t: t,
RouteRegister: routeRegister,
Mux: m,
TestServer: testServer,
}
}
// NewGetRequest creates a new GET request setup for test.
func (s *Server) NewGetRequest(target string) *http.Request {
return s.NewRequest(http.MethodGet, target, nil)
}
// NewPostRequest creates a new POST request setup for test.
func (s *Server) NewPostRequest(target string, body io.Reader) *http.Request {
return s.NewRequest(http.MethodPost, target, body)
}
// NewRequest creates a new request setup for test.
func (s *Server) NewRequest(method string, target string, body io.Reader) *http.Request {
s.t.Helper()
if !strings.HasPrefix(target, "/") {
target = "/" + target
}
target = s.TestServer.URL + target
req := httptest.NewRequest(method, target, body)
reqID := generateRequestIdentifier()
req = requestWithRequestIdentifier(req, reqID)
req.RequestURI = ""
return req
}
// Send sends a HTTP request to the test server and returns an HTTP response.
func (s *Server) Send(req *http.Request) (*http.Response, error) {
return http.DefaultClient.Do(req)
}
// SendJSON sets the Content-Type header to application/json and sends
// a HTTP request to the test server and returns an HTTP response.
// Suitable for POST/PUT/PATCH requests that sends request body as JSON.
func (s *Server) SendJSON(req *http.Request) (*http.Response, error) {
req.Header.Add("Content-Type", "application/json")
return s.Send(req)
}
func generateRequestIdentifier() string {
return uuid.NewString()
}
func requestWithRequestIdentifier(req *http.Request, id string) *http.Request {
req.Header.Set("X-GRAFANA-WEB-TEST-ID", id)
return req
}
func requestIdentifierFromRequest(req *http.Request) string {
return req.Header.Get("X-GRAFANA-WEB-TEST-ID")
}
func RequestWithWebContext(req *http.Request, c *contextmodel.ReqContext) *http.Request {
reqID := requestIdentifierFromRequest(req)
requests[reqID] = c
return req
}
func RequestWithSignedInUser(req *http.Request, usr *user.SignedInUser) *http.Request {
return RequestWithWebContext(req, &contextmodel.ReqContext{
SignedInUser: usr,
IsSignedIn: true,
})
}
func requestContextFromRequest(req *http.Request) *contextmodel.ReqContext {
reqID := requestIdentifierFromRequest(req)
val, exists := requests[reqID]
if !exists {
return nil
}
return val
}
func requestContextMiddleware() web.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c := ctxkey.Get(r.Context()).(*contextmodel.ReqContext)
ctx := requestContextFromRequest(r)
if ctx != nil {
c.SignedInUser = ctx.SignedInUser
c.UserToken = ctx.UserToken
c.IsSignedIn = ctx.IsSignedIn
c.IsRenderCall = ctx.IsRenderCall
c.AllowAnonymous = ctx.AllowAnonymous
Caching: Refactor enterprise query caching middleware to a wire service (#65616) * define initial service and add to wire * update caching service interface * add skipQueryCache header handler and update metrics query function to use it * add caching service as a dependency to query service * working caching impl * propagate cache status to frontend in response * beginning of improvements suggested by Lean - separate caching logic from query logic. * more changes to simplify query function * Decided to revert renaming of function * Remove error status from cache request * add extra documentation * Move query caching duration metric to query package * add a little bit of documentation * wip: convert resource caching * Change return type of query service QueryData to a QueryDataResponse with Headers * update codeowners * change X-Cache value to const * use resource caching in endpoint handlers * write resource headers to response even if it's not a cache hit * fix panic caused by lack of nil check * update unit test * remove NONE header - shouldn't show up in OSS * Convert everything to use the plugin middleware * revert a few more things * clean up unused vars * start reverting resource caching, start to implement in plugin middleware * revert more, fix typo * Update caching interfaces - resource caching now has a separate cache method * continue wiring up new resource caching conventions - still in progress * add more safety to implementation * remove some unused objects * remove some code that I left in by accident * add some comments, fix codeowners, fix duplicate registration * fix source of panic in resource middleware * Update client decorator test to provide an empty response object * create tests for caching middleware * fix unit test * Update pkg/services/caching/service.go Co-authored-by: Arati R. <33031346+suntala@users.noreply.github.com> * improve error message in error log * quick docs update * Remove use of mockery. Update return signature to return an explicit hit/miss bool * create unit test for empty request context * rename caching metrics to make it clear they pertain to caching * Update pkg/services/pluginsintegration/clientmiddleware/caching_middleware.go Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> * Add clarifying comments to cache skip middleware func * Add comment pointing to the resource cache update call * fix unit tests (missing dependency) * try to fix mystery syntax error * fix a panic * Caching: Introduce feature toggle to caching service refactor (#66323) * introduce new feature toggle * hide calls to new service behind a feature flag * remove licensing flag from toggle (misunderstood what it was for) * fix unit tests * rerun toggle gen --------- Co-authored-by: Arati R. <33031346+suntala@users.noreply.github.com> Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
2023-04-12 11:30:33 -05:00
c.SkipDSCache = ctx.SkipDSCache
c.RequestNonce = ctx.RequestNonce
c.PerfmonTimer = ctx.PerfmonTimer
c.LookupTokenErr = ctx.LookupTokenErr
}
next.ServeHTTP(w, r)
})
}
}