grafana/pkg/plugins/repo/service_test.go
Dave Henderson 6262c56132
chore(perf): Pre-allocate where possible (enable prealloc linter) (#88952)
* chore(perf): Pre-allocate where possible (enable prealloc linter)

Signed-off-by: Dave Henderson <dave.henderson@grafana.com>

* fix TestAlertManagers_buildRedactedAMs

Signed-off-by: Dave Henderson <dave.henderson@grafana.com>

* prealloc a slice that appeared after rebase

Signed-off-by: Dave Henderson <dave.henderson@grafana.com>

---------

Signed-off-by: Dave Henderson <dave.henderson@grafana.com>
2024-06-14 14:16:36 -04:00

219 lines
5.0 KiB
Go

package repo
import (
"archive/zip"
"bytes"
"context"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/plugins/log"
)
const (
dummyPluginJSON = `{ "id": "grafana-test-datasource" }`
)
func TestGetPluginArchive(t *testing.T) {
tcs := []struct {
name string
sha string
apiOpSys string
apiArch string
apiUrl string
err error
}{
{
name: "Happy path",
sha: "69f698961b6ea651211a187874434821c4727cc22de022e3a7059116d21c75b1",
},
{
name: "Incorrect SHA returns error",
sha: "1a2b3c",
err: ErrChecksumMismatchBase,
},
{
name: "Core plugin",
sha: "69f698961b6ea651211a187874434821c4727cc22de022e3a7059116d21c75b1",
apiOpSys: "any",
apiUrl: "https://github.com/grafana/grafana/tree/main/public/app/plugins/test",
err: ErrCorePluginBase,
},
{
name: "Decoupled core plugin",
sha: "69f698961b6ea651211a187874434821c4727cc22de022e3a7059116d21c75b1",
apiUrl: "https://github.com/grafana/grafana/tree/main/public/app/plugins/test",
},
}
pluginZip := createPluginArchive(t)
d, err := os.ReadFile(pluginZip.Name())
require.NoError(t, err)
t.Cleanup(func() {
err = pluginZip.Close()
require.NoError(t, err)
err = os.RemoveAll(pluginZip.Name())
require.NoError(t, err)
})
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
const (
pluginID = "grafana-test-datasource"
version = "1.0.2"
opSys = "darwin"
arch = "amd64"
grafanaVersion = "10.0.0"
)
srvd := srvData{
pluginID: pluginID,
version: version,
opSys: tc.apiOpSys,
arch: tc.apiArch,
url: tc.apiUrl,
grafanaVersion: grafanaVersion,
sha: tc.sha,
archive: d,
}
if srvd.opSys == "" {
srvd.opSys = opSys
}
if srvd.arch == "" && srvd.opSys != "any" {
srvd.arch = arch
}
srv := mockPluginVersionsAPI(t, srvd)
t.Cleanup(srv.Close)
m := NewManager(ManagerCfg{
SkipTLSVerify: false,
BaseURL: srv.URL,
Logger: log.NewTestPrettyLogger(),
})
co := NewCompatOpts(grafanaVersion, opSys, arch)
archive, err := m.GetPluginArchive(context.Background(), pluginID, version, co)
if tc.err != nil {
require.ErrorIs(t, err, tc.err)
return
}
require.NoError(t, err)
verifyArchive(t, archive)
})
}
}
func verifyArchive(t *testing.T, archive *PluginArchive) {
t.Helper()
require.NotNil(t, archive)
pJSON, err := archive.File.Open("plugin.json")
require.NoError(t, err)
defer func() { require.NoError(t, pJSON.Close()) }()
buf := new(bytes.Buffer)
_, err = buf.ReadFrom(pJSON)
require.NoError(t, err)
require.Equal(t, dummyPluginJSON, buf.String())
}
func createPluginArchive(t *testing.T) *os.File {
t.Helper()
pluginZip, err := os.CreateTemp(".", "test-plugin.zip")
require.NoError(t, err)
zipWriter := zip.NewWriter(pluginZip)
pJSON, err := zipWriter.Create("plugin.json")
require.NoError(t, err)
_, err = pJSON.Write([]byte(dummyPluginJSON))
require.NoError(t, err)
err = zipWriter.Close()
require.NoError(t, err)
return pluginZip
}
type srvData struct {
pluginID string
version string
opSys string
arch string
sha string
grafanaVersion string
archive []byte
url string
}
func mockPluginVersionsAPI(t *testing.T, data srvData) *httptest.Server {
t.Helper()
mux := http.NewServeMux()
// mock plugin version data
mux.HandleFunc(fmt.Sprintf("/%s/versions", data.pluginID), func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, data.grafanaVersion, r.Header.Get("grafana-version"))
require.NotNil(t, fmt.Sprintf("grafana %s", data.grafanaVersion), r.Header.Get("User-Agent"))
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
platform := data.opSys
if data.arch != "" {
platform += "-" + data.arch
}
_, _ = w.Write([]byte(fmt.Sprintf(`
{
"items": [{
"version": "%s",
"packages": {
"%s": {
"sha256": "%s"
}
},
"url": "%s"
}]
}
`, data.version, platform, data.sha, data.url),
))
})
// mock plugin archive
mux.HandleFunc(fmt.Sprintf("/%s/versions/%s/download", data.pluginID, data.version), func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/zip")
_, _ = w.Write(data.archive)
})
return httptest.NewServer(mux)
}
type versionArg struct {
version string
arch []string
}
func createPluginVersions(versions ...versionArg) []Version {
vs := make([]Version, len(versions))
for i, version := range versions {
ver := Version{
Version: version.version,
}
if version.arch != nil {
ver.Arch = map[string]ArchMeta{}
for _, arch := range version.arch {
ver.Arch[arch] = ArchMeta{
SHA256: fmt.Sprintf("sha256_%s", arch),
}
}
}
vs[i] = ver
}
return vs
}