The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/publicdashboards/api/middleware_test.go

187 lines
5.9 KiB

package api
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"errors"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/publicdashboards/service"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
var validAccessToken, _ = service.GenerateAccessToken()
func TestRequiresExistingAccessToken(t *testing.T) {
tests := []struct {
Name string
Path string
AccessTokenExists bool
AccessTokenExistsErr error
AccessToken string
ExpectedResponseCode int
}{
{
Name: "Returns 200 when public dashboard with access token exists",
Path: "/api/public/ma/events/myAccesstoken",
AccessTokenExists: true,
AccessTokenExistsErr: nil,
AccessToken: validAccessToken,
ExpectedResponseCode: http.StatusOK,
},
{
Name: "Returns 400 when access token is empty",
Path: "/api/public/ma/events/",
AccessTokenExists: false,
AccessTokenExistsErr: nil,
AccessToken: "",
ExpectedResponseCode: http.StatusBadRequest,
},
{
Name: "Returns 400 when invalid access token",
Path: "/api/public/ma/events/myAccesstoken",
AccessTokenExists: false,
AccessTokenExistsErr: nil,
AccessToken: "invalidAccessToken",
ExpectedResponseCode: http.StatusBadRequest,
},
{
Name: "Returns 404 when public dashboard with access token does not exist",
Path: "/api/public/ma/events/myAccesstoken",
AccessTokenExists: false,
AccessTokenExistsErr: nil,
AccessToken: validAccessToken,
ExpectedResponseCode: http.StatusNotFound,
},
{
Name: "Returns 500 when public dashboard service gives an error",
Path: "/api/public/ma/events/myAccesstoken",
AccessTokenExists: false,
AccessTokenExistsErr: fmt.Errorf("error not found"),
AccessToken: validAccessToken,
ExpectedResponseCode: http.StatusInternalServerError,
},
}
for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
publicdashboardService := &publicdashboards.FakePublicDashboardService{}
publicdashboardService.On("ExistsEnabledByAccessToken", mock.Anything, mock.Anything).Return(tt.AccessTokenExists, tt.AccessTokenExistsErr)
params := map[string]string{":accessToken": tt.AccessToken}
mw := RequiresExistingAccessToken(publicdashboardService)
_, resp := runMw(t, nil, "GET", tt.Path, params, mw)
require.Equal(t, tt.ExpectedResponseCode, resp.Code)
})
}
}
func TestSetPublicDashboardOrgIdOnContext(t *testing.T) {
tests := []struct {
Name string
AccessToken string
OrgIdResp int64
ErrorResp error
ExpectedOrgId int64
}{
{
Name: "Adds orgId for enabled public dashboard",
AccessToken: validAccessToken,
OrgIdResp: 7,
ErrorResp: nil,
ExpectedOrgId: 7,
},
{
Name: "Does not set orgId or fail with invalid accessToken",
AccessToken: "invalidAccessToken",
OrgIdResp: 0,
ErrorResp: nil,
ExpectedOrgId: 0,
},
{
Name: "Does not set orgId or fail with disabled public dashboard",
AccessToken: validAccessToken,
OrgIdResp: 0,
ErrorResp: nil,
ExpectedOrgId: 0,
},
{
Name: "Does not set orgId or fail with error querying public dashboard",
AccessToken: validAccessToken,
OrgIdResp: 0,
ErrorResp: errors.New("database error of some sort"),
ExpectedOrgId: 0,
},
{
Name: "Does not set orgId or fail with missing public dashboard",
AccessToken: validAccessToken,
OrgIdResp: 0,
ErrorResp: nil,
ExpectedOrgId: 0,
},
}
for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
publicdashboardService := &publicdashboards.FakePublicDashboardService{}
publicdashboardService.On("GetOrgIdByAccessToken", mock.Anything, tt.AccessToken).Return(
tt.OrgIdResp,
tt.ErrorResp,
)
params := map[string]string{":accessToken": tt.AccessToken}
mw := SetPublicDashboardOrgIdOnContext(publicdashboardService)
ctx, _ := runMw(t, nil, "GET", "/public-dashboard/myaccesstoken", params, mw)
assert.Equal(t, tt.ExpectedOrgId, ctx.OrgID)
})
}
}
func TestSetPublicDashboardFlag(t *testing.T) {
t.Run("Adds context.IsPublicDashboardView=true to request", func(t *testing.T) {
ctx := &contextmodel.ReqContext{}
SetPublicDashboardFlag(ctx)
assert.True(t, ctx.IsPublicDashboardView)
})
}
// This is a helper to test middleware. It handles creating a
// proper contextmodel.ReqContext, setting web parameters, executing middleware, and
// returning a response. Response will default to result of
// httptest.NewRecorder() return value and will only change if modified by the
// middlware as this will no accept a handler method
func runMw(t *testing.T, ctx *contextmodel.ReqContext, httpmethod string, path string, webparams map[string]string, mw func(c *contextmodel.ReqContext)) (*contextmodel.ReqContext, *httptest.ResponseRecorder) {
// create valid request context and set 0 values if they don't exist
if ctx == nil {
ctx = &contextmodel.ReqContext{}
}
if ctx.Context == nil {
ctx.Context = &web.Context{}
}
if ctx.SignedInUser == nil {
ctx.SignedInUser = &user.SignedInUser{}
}
// create request and add params
request, err := http.NewRequest(httpmethod, path, nil)
require.NoError(t, err)
request = web.SetURLParams(request, webparams)
ctx.Req = request
// setup response recorder to return
response := httptest.NewRecorder()
ctx.Context.Resp = web.NewResponseWriter("GET", response)
// run middleware
mw(ctx)
// return result
return ctx, response
}