mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 16:15:42 -06:00
This PR refactors how we add the orgId to the context on a public dashboard paths. We also split out accessToken handling into its own package and rework status code for "RequiresValidAccessToken". We will be modeling all endpoints to use these status codes going forward. Additionally, it includes a scaffold for better middleware testing and refactors existing tests to table drive tests.
188 lines
5.8 KiB
Go
188 lines
5.8 KiB
Go
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"errors"
|
|
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
|
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
|
"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, _ = tokens.GenerateAccessToken()
|
|
|
|
func TestRequiresValidAccessToken(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("AccessTokenExists", mock.Anything, mock.Anything).Return(tt.AccessTokenExists, tt.AccessTokenExistsErr)
|
|
params := map[string]string{":accessToken": tt.AccessToken}
|
|
mw := RequiresValidAccessToken(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("GetPublicDashboardOrgId", 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 := &models.ReqContext{}
|
|
SetPublicDashboardFlag(ctx)
|
|
assert.True(t, ctx.IsPublicDashboardView)
|
|
})
|
|
}
|
|
|
|
// This is a helper to test middleware. It handles creating a
|
|
// proper models.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 *models.ReqContext, httpmethod string, path string, webparams map[string]string, mw func(c *models.ReqContext)) (*models.ReqContext, *httptest.ResponseRecorder) {
|
|
// create valid request context and set 0 values if they don't exist
|
|
if ctx == nil {
|
|
ctx = &models.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
|
|
}
|