Merge branch 'v9.0.x' of github.com:grafana/grafana into v9.0.x
This commit is contained in:
+87
-71
@@ -506,91 +506,107 @@ func (hs *HTTPServer) NotificationTest(c *models.ReqContext) response.Response {
|
||||
}
|
||||
|
||||
// POST /api/alerts/:alertId/pause
|
||||
func (hs *HTTPServer) PauseAlert(c *models.ReqContext) response.Response {
|
||||
dto := dtos.PauseAlertCommand{}
|
||||
if err := web.Bind(c.Req, &dto); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
}
|
||||
alertID, err := strconv.ParseInt(web.Params(c.Req)[":alertId"], 10, 64)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusBadRequest, "alertId is invalid", err)
|
||||
}
|
||||
result := make(map[string]interface{})
|
||||
result["alertId"] = alertID
|
||||
|
||||
query := models.GetAlertByIdQuery{Id: alertID}
|
||||
if err := hs.SQLStore.GetAlertById(c.Req.Context(), &query); err != nil {
|
||||
return response.Error(500, "Get Alert failed", err)
|
||||
func (hs *HTTPServer) PauseAlert(legacyAlertingEnabled *bool) func(c *models.ReqContext) response.Response {
|
||||
if legacyAlertingEnabled == nil || !*legacyAlertingEnabled {
|
||||
return func(_ *models.ReqContext) response.Response {
|
||||
return response.Error(http.StatusBadRequest, "legacy alerting is disabled, so this call has no effect.", nil)
|
||||
}
|
||||
}
|
||||
|
||||
guardian := guardian.New(c.Req.Context(), query.Result.DashboardId, c.OrgId, c.SignedInUser)
|
||||
if canEdit, err := guardian.CanEdit(); err != nil || !canEdit {
|
||||
return func(c *models.ReqContext) response.Response {
|
||||
dto := dtos.PauseAlertCommand{}
|
||||
if err := web.Bind(c.Req, &dto); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
}
|
||||
alertID, err := strconv.ParseInt(web.Params(c.Req)[":alertId"], 10, 64)
|
||||
if err != nil {
|
||||
return response.Error(500, "Error while checking permissions for Alert", err)
|
||||
return response.Error(http.StatusBadRequest, "alertId is invalid", err)
|
||||
}
|
||||
result := make(map[string]interface{})
|
||||
result["alertId"] = alertID
|
||||
|
||||
query := models.GetAlertByIdQuery{Id: alertID}
|
||||
if err := hs.SQLStore.GetAlertById(c.Req.Context(), &query); err != nil {
|
||||
return response.Error(500, "Get Alert failed", err)
|
||||
}
|
||||
|
||||
return response.Error(403, "Access denied to this dashboard and alert", nil)
|
||||
}
|
||||
guardian := guardian.New(c.Req.Context(), query.Result.DashboardId, c.OrgId, c.SignedInUser)
|
||||
if canEdit, err := guardian.CanEdit(); err != nil || !canEdit {
|
||||
if err != nil {
|
||||
return response.Error(500, "Error while checking permissions for Alert", err)
|
||||
}
|
||||
|
||||
// Alert state validation
|
||||
if query.Result.State != models.AlertStatePaused && !dto.Paused {
|
||||
result["state"] = "un-paused"
|
||||
result["message"] = "Alert is already un-paused"
|
||||
return response.JSON(http.StatusOK, result)
|
||||
} else if query.Result.State == models.AlertStatePaused && dto.Paused {
|
||||
result["state"] = models.AlertStatePaused
|
||||
result["message"] = "Alert is already paused"
|
||||
return response.Error(403, "Access denied to this dashboard and alert", nil)
|
||||
}
|
||||
|
||||
// Alert state validation
|
||||
if query.Result.State != models.AlertStatePaused && !dto.Paused {
|
||||
result["state"] = "un-paused"
|
||||
result["message"] = "Alert is already un-paused"
|
||||
return response.JSON(http.StatusOK, result)
|
||||
} else if query.Result.State == models.AlertStatePaused && dto.Paused {
|
||||
result["state"] = models.AlertStatePaused
|
||||
result["message"] = "Alert is already paused"
|
||||
return response.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
cmd := models.PauseAlertCommand{
|
||||
OrgId: c.OrgId,
|
||||
AlertIds: []int64{alertID},
|
||||
Paused: dto.Paused,
|
||||
}
|
||||
|
||||
if err := hs.SQLStore.PauseAlert(c.Req.Context(), &cmd); err != nil {
|
||||
return response.Error(500, "", err)
|
||||
}
|
||||
|
||||
resp := models.AlertStateUnknown
|
||||
pausedState := "un-paused"
|
||||
if cmd.Paused {
|
||||
resp = models.AlertStatePaused
|
||||
pausedState = "paused"
|
||||
}
|
||||
|
||||
result["state"] = resp
|
||||
result["message"] = "Alert " + pausedState
|
||||
return response.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
cmd := models.PauseAlertCommand{
|
||||
OrgId: c.OrgId,
|
||||
AlertIds: []int64{alertID},
|
||||
Paused: dto.Paused,
|
||||
}
|
||||
|
||||
if err := hs.SQLStore.PauseAlert(c.Req.Context(), &cmd); err != nil {
|
||||
return response.Error(500, "", err)
|
||||
}
|
||||
|
||||
resp := models.AlertStateUnknown
|
||||
pausedState := "un-paused"
|
||||
if cmd.Paused {
|
||||
resp = models.AlertStatePaused
|
||||
pausedState = "paused"
|
||||
}
|
||||
|
||||
result["state"] = resp
|
||||
result["message"] = "Alert " + pausedState
|
||||
return response.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// POST /api/admin/pause-all-alerts
|
||||
func (hs *HTTPServer) PauseAllAlerts(c *models.ReqContext) response.Response {
|
||||
dto := dtos.PauseAllAlertsCommand{}
|
||||
if err := web.Bind(c.Req, &dto); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
}
|
||||
updateCmd := models.PauseAllAlertCommand{
|
||||
Paused: dto.Paused,
|
||||
func (hs *HTTPServer) PauseAllAlerts(legacyAlertingEnabled *bool) func(c *models.ReqContext) response.Response {
|
||||
if legacyAlertingEnabled == nil || !*legacyAlertingEnabled {
|
||||
return func(_ *models.ReqContext) response.Response {
|
||||
return response.Error(http.StatusBadRequest, "legacy alerting is disabled, so this call has no effect.", nil)
|
||||
}
|
||||
}
|
||||
|
||||
if err := hs.SQLStore.PauseAllAlerts(c.Req.Context(), &updateCmd); err != nil {
|
||||
return response.Error(500, "Failed to pause alerts", err)
|
||||
}
|
||||
return func(c *models.ReqContext) response.Response {
|
||||
dto := dtos.PauseAllAlertsCommand{}
|
||||
if err := web.Bind(c.Req, &dto); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
}
|
||||
updateCmd := models.PauseAllAlertCommand{
|
||||
Paused: dto.Paused,
|
||||
}
|
||||
|
||||
resp := models.AlertStatePending
|
||||
pausedState := "un paused"
|
||||
if updateCmd.Paused {
|
||||
resp = models.AlertStatePaused
|
||||
pausedState = "paused"
|
||||
}
|
||||
if err := hs.SQLStore.PauseAllAlerts(c.Req.Context(), &updateCmd); err != nil {
|
||||
return response.Error(500, "Failed to pause alerts", err)
|
||||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
"state": resp,
|
||||
"message": "alerts " + pausedState,
|
||||
"alertsAffected": updateCmd.ResultCount,
|
||||
}
|
||||
resp := models.AlertStatePending
|
||||
pausedState := "un paused"
|
||||
if updateCmd.Paused {
|
||||
resp = models.AlertStatePaused
|
||||
pausedState = "paused"
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, result)
|
||||
result := map[string]interface{}{
|
||||
"state": resp,
|
||||
"message": "alerts " + pausedState,
|
||||
"alertsAffected": updateCmd.ResultCount,
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,9 @@ func postAlertScenario(t *testing.T, hs *HTTPServer, desc string, url string, ro
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = role
|
||||
|
||||
return hs.PauseAlert(c)
|
||||
legacyAlertingEnabled := new(bool)
|
||||
*legacyAlertingEnabled = true
|
||||
return hs.PauseAlert(legacyAlertingEnabled)(c)
|
||||
})
|
||||
|
||||
sc.m.Post(routePattern, sc.defaultHandler)
|
||||
|
||||
+9
-6
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
@@ -325,10 +326,12 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
apiRoute.Any("/plugins/:pluginId/resources/*", hs.CallResource)
|
||||
apiRoute.Get("/plugins/errors", routing.Wrap(hs.GetPluginErrorsList))
|
||||
|
||||
apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) {
|
||||
pluginRoute.Post("/:pluginId/install", routing.Wrap(hs.InstallPlugin))
|
||||
pluginRoute.Post("/:pluginId/uninstall", routing.Wrap(hs.UninstallPlugin))
|
||||
}, reqGrafanaAdmin)
|
||||
if hs.Cfg.PluginAdminEnabled && !hs.Cfg.PluginAdminExternalManageEnabled {
|
||||
apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) {
|
||||
pluginRoute.Post("/:pluginId/install", routing.Wrap(hs.InstallPlugin))
|
||||
pluginRoute.Post("/:pluginId/uninstall", routing.Wrap(hs.UninstallPlugin))
|
||||
}, reqGrafanaAdmin)
|
||||
}
|
||||
|
||||
apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) {
|
||||
pluginRoute.Get("/:pluginId/dashboards/", routing.Wrap(hs.GetPluginDashboards))
|
||||
@@ -449,7 +452,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
|
||||
apiRoute.Group("/alerts", func(alertsRoute routing.RouteRegister) {
|
||||
alertsRoute.Post("/test", routing.Wrap(hs.AlertTest))
|
||||
alertsRoute.Post("/:alertId/pause", reqEditorRole, routing.Wrap(hs.PauseAlert))
|
||||
alertsRoute.Post("/:alertId/pause", reqEditorRole, routing.Wrap(hs.PauseAlert(setting.AlertingEnabled)))
|
||||
alertsRoute.Get("/:alertId", hs.ValidateOrgAlert, routing.Wrap(hs.GetAlert))
|
||||
alertsRoute.Get("/", routing.Wrap(hs.GetAlerts))
|
||||
alertsRoute.Get("/states-for-dashboard", routing.Wrap(hs.GetAlertStatesForDashboard))
|
||||
@@ -543,7 +546,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
adminRoute.Get("/settings/features", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionSettingsRead)), hs.Features.HandleGetSettings)
|
||||
}
|
||||
adminRoute.Get("/stats", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionServerStatsRead)), routing.Wrap(hs.AdminGetStats))
|
||||
adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, routing.Wrap(hs.PauseAllAlerts))
|
||||
adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, routing.Wrap(hs.PauseAllAlerts(setting.AlertingEnabled)))
|
||||
|
||||
if hs.ThumbService != nil && hs.Features.IsEnabled(featuremgmt.FlagDashboardPreviewsAdmin) {
|
||||
adminRoute.Post("/crawler/start", reqGrafanaAdmin, routing.Wrap(hs.ThumbService.StartCrawler))
|
||||
|
||||
@@ -453,7 +453,7 @@ func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboa
|
||||
|
||||
// GetHomeDashboard returns the home dashboard.
|
||||
func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) response.Response {
|
||||
prefsQuery := pref.GetPreferenceWithDefaultsQuery{OrgID: c.OrgId, UserID: c.SignedInUser.UserId}
|
||||
prefsQuery := pref.GetPreferenceWithDefaultsQuery{OrgID: c.OrgId, UserID: c.SignedInUser.UserId, Teams: c.Teams}
|
||||
homePage := hs.Cfg.HomePage
|
||||
|
||||
preference, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery)
|
||||
|
||||
@@ -266,24 +266,28 @@ func (hs *HTTPServer) DeleteDashboardSnapshot(c *models.ReqContext) response.Res
|
||||
return response.Error(404, "Failed to get dashboard snapshot", nil)
|
||||
}
|
||||
|
||||
dashboardID := query.Result.Dashboard.Get("id").MustInt64()
|
||||
|
||||
guardian := guardian.New(c.Req.Context(), dashboardID, c.OrgId, c.SignedInUser)
|
||||
canEdit, err := guardian.CanEdit()
|
||||
// check for permissions only if the dahboard is found
|
||||
if err != nil && !errors.Is(err, models.ErrDashboardNotFound) {
|
||||
return response.Error(500, "Error while checking permissions for snapshot", err)
|
||||
}
|
||||
|
||||
if !canEdit && query.Result.UserId != c.SignedInUser.UserId && !errors.Is(err, models.ErrDashboardNotFound) {
|
||||
return response.Error(403, "Access denied to this snapshot", nil)
|
||||
}
|
||||
|
||||
if query.Result.External {
|
||||
err := deleteExternalDashboardSnapshot(query.Result.ExternalDeleteUrl)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed to delete external dashboard", err)
|
||||
}
|
||||
} else {
|
||||
// When creating an external snapshot, its dashboard content is empty. This means that the mustInt here returns a 0,
|
||||
// which before RBAC would result in a dashboard which has no ACL. A dashboard without an ACL would fallback
|
||||
// to the user’s org role, which for editors and admins would essentially always be allowed here. With RBAC,
|
||||
// all permissions must be explicit, so the lack of a rule for dashboard 0 means the guardian will reject.
|
||||
dashboardID := query.Result.Dashboard.Get("id").MustInt64()
|
||||
|
||||
guardian := guardian.New(c.Req.Context(), dashboardID, c.OrgId, c.SignedInUser)
|
||||
canEdit, err := guardian.CanEdit()
|
||||
// check for permissions only if the dahboard is found
|
||||
if err != nil && !errors.Is(err, models.ErrDashboardNotFound) {
|
||||
return response.Error(500, "Error while checking permissions for snapshot", err)
|
||||
}
|
||||
|
||||
if !canEdit && query.Result.UserId != c.SignedInUser.UserId && !errors.Is(err, models.ErrDashboardNotFound) {
|
||||
return response.Error(403, "Access denied to this snapshot", nil)
|
||||
}
|
||||
}
|
||||
|
||||
cmd := &models.DeleteDashboardSnapshotCommand{DeleteKey: query.Result.DeleteKey}
|
||||
|
||||
@@ -56,18 +56,14 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
|
||||
t.Run("When user has editor role and is not in the ACL", func(t *testing.T) {
|
||||
loggedInUserScenarioWithRole(t, "Should not be able to delete snapshot when calling DELETE on",
|
||||
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
var externalRequest *http.Request
|
||||
mockSnapshotResult := setUpSnapshotTest(t)
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
externalRequest = req
|
||||
})
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
mockSnapshotResult.ExternalDeleteUrl = ""
|
||||
mockSnapshotResult.External = false
|
||||
sc.handlerFunc = hs.DeleteDashboardSnapshot
|
||||
guardian.InitLegacyGuardian(sc.sqlStore)
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
require.Nil(t, externalRequest)
|
||||
}, sqlmock)
|
||||
})
|
||||
|
||||
|
||||
@@ -1115,7 +1115,7 @@ func (m *mockLibraryPanelService) ConnectLibraryPanelsForDashboard(c context.Con
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockLibraryPanelService) ImportLibraryPanelsForDashboard(c context.Context, signedInUser *models.SignedInUser, dash *models.Dashboard, folderID int64) error {
|
||||
func (m *mockLibraryPanelService) ImportLibraryPanelsForDashboard(c context.Context, signedInUser *models.SignedInUser, libraryPanels *simplejson.Json, panels []interface{}, folderID int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+21
-6
@@ -7,20 +7,18 @@ import (
|
||||
)
|
||||
|
||||
type fakePluginStore struct {
|
||||
plugins.Store
|
||||
|
||||
plugins map[string]plugins.PluginDTO
|
||||
}
|
||||
|
||||
func (pr fakePluginStore) Plugin(_ context.Context, pluginID string) (plugins.PluginDTO, bool) {
|
||||
p, exists := pr.plugins[pluginID]
|
||||
func (ps fakePluginStore) Plugin(_ context.Context, pluginID string) (plugins.PluginDTO, bool) {
|
||||
p, exists := ps.plugins[pluginID]
|
||||
|
||||
return p, exists
|
||||
}
|
||||
|
||||
func (pr fakePluginStore) Plugins(_ context.Context, pluginTypes ...plugins.Type) []plugins.PluginDTO {
|
||||
func (ps fakePluginStore) Plugins(_ context.Context, pluginTypes ...plugins.Type) []plugins.PluginDTO {
|
||||
var result []plugins.PluginDTO
|
||||
for _, v := range pr.plugins {
|
||||
for _, v := range ps.plugins {
|
||||
for _, t := range pluginTypes {
|
||||
if v.Type == t {
|
||||
result = append(result, v)
|
||||
@@ -31,6 +29,23 @@ func (pr fakePluginStore) Plugins(_ context.Context, pluginTypes ...plugins.Type
|
||||
return result
|
||||
}
|
||||
|
||||
func (ps fakePluginStore) Add(_ context.Context, pluginID, version string) error {
|
||||
ps.plugins[pluginID] = plugins.PluginDTO{
|
||||
JSONData: plugins.JSONData{
|
||||
ID: pluginID,
|
||||
Info: plugins.Info{
|
||||
Version: version,
|
||||
},
|
||||
},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps fakePluginStore) Remove(_ context.Context, pluginID string) error {
|
||||
delete(ps.plugins, pluginID)
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeRendererManager struct {
|
||||
plugins.RendererManager
|
||||
}
|
||||
|
||||
+80
-2
@@ -4,25 +4,103 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log/logtest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/log/logtest"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web/webtest"
|
||||
)
|
||||
|
||||
func Test_PluginsInstallAndUninstall(t *testing.T) {
|
||||
type tc struct {
|
||||
pluginAdminEnabled bool
|
||||
pluginAdminExternalManageEnabled bool
|
||||
expectedHTTPStatus int
|
||||
expectedHTTPBody string
|
||||
}
|
||||
tcs := []tc{
|
||||
{pluginAdminEnabled: true, pluginAdminExternalManageEnabled: true, expectedHTTPStatus: 404, expectedHTTPBody: "404 page not found\n"},
|
||||
{pluginAdminEnabled: true, pluginAdminExternalManageEnabled: false, expectedHTTPStatus: 200, expectedHTTPBody: ""},
|
||||
{pluginAdminEnabled: false, pluginAdminExternalManageEnabled: true, expectedHTTPStatus: 404, expectedHTTPBody: "404 page not found\n"},
|
||||
{pluginAdminEnabled: false, pluginAdminExternalManageEnabled: false, expectedHTTPStatus: 404, expectedHTTPBody: "404 page not found\n"},
|
||||
}
|
||||
|
||||
testName := func(action string, testCase tc) string {
|
||||
return fmt.Sprintf("%s request returns %d when adminEnabled: %t and externalEnabled: %t",
|
||||
action, testCase.expectedHTTPStatus, testCase.pluginAdminEnabled, testCase.pluginAdminExternalManageEnabled)
|
||||
}
|
||||
|
||||
ps := fakePluginStore{
|
||||
plugins: make(map[string]plugins.PluginDTO),
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = &setting.Cfg{
|
||||
PluginAdminEnabled: tc.pluginAdminEnabled,
|
||||
PluginAdminExternalManageEnabled: tc.pluginAdminExternalManageEnabled,
|
||||
}
|
||||
hs.pluginStore = ps
|
||||
})
|
||||
|
||||
t.Run(testName("Install", tc), func(t *testing.T) {
|
||||
req := srv.NewPostRequest("/api/plugins/test/install", strings.NewReader("{ \"version\": \"1.0.2\" }"))
|
||||
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, OrgRole: models.ROLE_EDITOR, IsGrafanaAdmin: true})
|
||||
resp, err := srv.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
body := new(strings.Builder)
|
||||
_, err = io.Copy(body, resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expectedHTTPBody, body.String())
|
||||
require.NoError(t, resp.Body.Close())
|
||||
require.Equal(t, tc.expectedHTTPStatus, resp.StatusCode)
|
||||
|
||||
if tc.expectedHTTPStatus == 200 {
|
||||
require.Equal(t, plugins.PluginDTO{
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "test",
|
||||
Info: plugins.Info{
|
||||
Version: "1.0.2",
|
||||
},
|
||||
},
|
||||
}, ps.plugins["test"])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run(testName("Uninstall", tc), func(t *testing.T) {
|
||||
req := srv.NewPostRequest("/api/plugins/test/uninstall", strings.NewReader("{}"))
|
||||
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, OrgRole: models.ROLE_VIEWER, IsGrafanaAdmin: true})
|
||||
resp, err := srv.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
body := new(strings.Builder)
|
||||
_, err = io.Copy(body, resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expectedHTTPBody, body.String())
|
||||
require.NoError(t, resp.Body.Close())
|
||||
require.Equal(t, tc.expectedHTTPStatus, resp.StatusCode)
|
||||
|
||||
if tc.expectedHTTPStatus == 200 {
|
||||
require.Empty(t, ps.plugins)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetPluginAssets(t *testing.T) {
|
||||
pluginID := "test-plugin"
|
||||
pluginDir := "."
|
||||
|
||||
Reference in New Issue
Block a user