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/tests/api/plugins/api_plugins_test.go

156 lines
4.3 KiB

package plugins
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"path/filepath"
"testing"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/tests/testinfra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const (
usernameAdmin = "admin"
usernameNonAdmin = "nonAdmin"
defaultPassword = "password"
)
var updateSnapshotFlag = false
func TestPlugins(t *testing.T) {
dir, cfgPath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
PluginAdminEnabled: true,
})
grafanaListedAddr, store := testinfra.StartGrafana(t, dir, cfgPath)
type testCase struct {
desc string
url string
expStatus int
expRespPath string
}
t.Run("Install", func(t *testing.T) {
store.Bus = bus.GetBus()
createUser(t, store, models.CreateUserCommand{Login: usernameNonAdmin, Password: defaultPassword, IsAdmin: false})
createUser(t, store, models.CreateUserCommand{Login: usernameAdmin, Password: defaultPassword, IsAdmin: true})
t.Run("Request is forbidden if not from an admin", func(t *testing.T) {
status, body := makePostRequest(t, grafanaAPIURL(usernameNonAdmin, grafanaListedAddr, "plugins/grafana-plugin/install"))
assert.Equal(t, 403, status)
assert.Equal(t, "Permission denied", body["message"])
status, body = makePostRequest(t, grafanaAPIURL(usernameNonAdmin, grafanaListedAddr, "plugins/grafana-plugin/uninstall"))
assert.Equal(t, 403, status)
assert.Equal(t, "Permission denied", body["message"])
})
t.Run("Request is not forbidden if from an admin", func(t *testing.T) {
statusCode, body := makePostRequest(t, grafanaAPIURL(usernameAdmin, grafanaListedAddr, "plugins/test/install"))
assert.Equal(t, 404, statusCode)
assert.Equal(t, "Plugin not found", body["message"])
statusCode, body = makePostRequest(t, grafanaAPIURL(usernameAdmin, grafanaListedAddr, "plugins/test/uninstall"))
assert.Equal(t, 404, statusCode)
assert.Equal(t, "Plugin not installed", body["message"])
})
})
t.Run("List", func(t *testing.T) {
testCases := []testCase{
{
desc: "should return all loaded core and bundled plugins",
url: "http://%s/api/plugins",
expStatus: http.StatusOK,
expRespPath: "expectedListResp.json",
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
url := fmt.Sprintf(tc.url, grafanaListedAddr)
// nolint:gosec
resp, err := http.Get(url)
t.Cleanup(func() {
require.NoError(t, resp.Body.Close())
})
require.NoError(t, err)
require.Equal(t, tc.expStatus, resp.StatusCode)
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
expResp := expectedResp(t, tc.expRespPath)
same := assert.JSONEq(t, expResp, string(b))
if !same {
if updateSnapshotFlag {
t.Log("updating snapshot results")
updateRespSnapshot(t, tc.expRespPath, string(b))
}
t.FailNow()
}
})
}
})
}
func createUser(t *testing.T, store *sqlstore.SQLStore, cmd models.CreateUserCommand) {
t.Helper()
_, err := store.CreateUser(context.Background(), cmd)
require.NoError(t, err)
}
func makePostRequest(t *testing.T, URL string) (int, map[string]interface{}) {
t.Helper()
// nolint:gosec
resp, err := http.Post(URL, "application/json", bytes.NewBufferString(""))
require.NoError(t, err)
t.Cleanup(func() {
_ = resp.Body.Close()
fmt.Printf("Failed to close response body err: %s", err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
var body = make(map[string]interface{})
err = json.Unmarshal(b, &body)
require.NoError(t, err)
return resp.StatusCode, body
}
func grafanaAPIURL(username string, grafanaListedAddr string, path string) string {
return fmt.Sprintf("http://%s:%s@%s/api/%s", username, defaultPassword, grafanaListedAddr, path)
}
func expectedResp(t *testing.T, filename string) string {
//nolint:GOSEC
contents, err := ioutil.ReadFile(filepath.Join("data", filename))
if err != nil {
t.Errorf("failed to load %s: %v", filename, err)
}
return string(contents)
}
func updateRespSnapshot(t *testing.T, filename string, body string) {
err := ioutil.WriteFile(filepath.Join("data", filename), []byte(body), 0600)
if err != nil {
t.Errorf("error writing snapshot %s: %v", filename, err)
}
}