Advisor: Avoid one GCOM request per plugin (#105180)

pull/105329/head
Andres Martinez Gotor 1 week ago committed by GitHub
parent cb28213f1d
commit 0d4884cb3b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      apps/advisor/pkg/app/checks/authchecks/check.go
  2. 23
      apps/advisor/pkg/app/checks/datasourcecheck/check.go
  3. 41
      apps/advisor/pkg/app/checks/datasourcecheck/check_test.go
  4. 3
      apps/advisor/pkg/app/checks/ifaces.go
  5. 46
      apps/advisor/pkg/app/checks/plugincheck/check.go
  6. 76
      apps/advisor/pkg/app/checks/plugincheck/check_test.go
  7. 8
      apps/advisor/pkg/app/utils.go
  8. 4
      apps/advisor/pkg/app/utils_test.go
  9. 4
      pkg/plugins/manager/fakes/fakes.go
  10. 4
      pkg/plugins/repo/ifaces.go
  11. 7
      pkg/plugins/repo/models.go
  12. 10
      pkg/plugins/repo/service.go
  13. 22
      pkg/plugins/repo/service_test.go

@ -28,6 +28,10 @@ func (c *check) ID() string {
return CheckID
}
func (c *check) Init(ctx context.Context) error {
return nil
}
func (c *check) Steps() []checks.Step {
return []checks.Step{
&listFormatValidation{},

@ -32,6 +32,7 @@ type check struct {
PluginClient plugins.Client
PluginRepo repo.Service
GrafanaVersion string
pluginIndex map[string]repo.PluginInfo
}
func New(
@ -79,6 +80,19 @@ func (c *check) ID() string {
return CheckID
}
func (c *check) Init(ctx context.Context) error {
compatOpts := repo.NewCompatOpts(c.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH)
plugins, err := c.PluginRepo.GetPluginsInfo(ctx, compatOpts)
if err != nil {
return err
}
c.pluginIndex = make(map[string]repo.PluginInfo)
for _, p := range plugins {
c.pluginIndex[p.Slug] = p
}
return nil
}
func (c *check) Steps() []checks.Step {
return []checks.Step{
&uidValidationStep{},
@ -88,8 +102,8 @@ func (c *check) Steps() []checks.Step {
},
&missingPluginStep{
PluginStore: c.PluginStore,
PluginRepo: c.PluginRepo,
GrafanaVersion: c.GrafanaVersion,
pluginIndex: c.pluginIndex,
},
}
}
@ -207,8 +221,8 @@ func (s *healthCheckStep) Run(ctx context.Context, log logging.Logger, obj *advi
type missingPluginStep struct {
PluginStore pluginstore.Store
PluginRepo repo.Service
GrafanaVersion string
pluginIndex map[string]repo.PluginInfo
}
func (s *missingPluginStep) Title() string {
@ -241,9 +255,8 @@ func (s *missingPluginStep) Run(ctx context.Context, log logging.Logger, obj *ad
Url: fmt.Sprintf("/connections/datasources/edit/%s", ds.UID),
},
}
compatOpts := repo.NewCompatOpts(s.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH)
_, err := s.PluginRepo.PluginInfo(ctx, ds.Type, compatOpts)
if err == nil {
_, ok := s.pluginIndex[ds.Type]
if ok {
// Plugin is available in the repo
links = append(links, advisor.CheckErrorLink{
Message: "Install plugin",

@ -2,7 +2,6 @@ package datasourcecheck
import (
"context"
"errors"
"testing"
"github.com/grafana/grafana-app-sdk/logging"
@ -26,6 +25,10 @@ func runChecks(check *check) ([]advisor.CheckReportFailure, error) {
}
failures := []advisor.CheckReportFailure{}
err = check.Init(ctx)
if err != nil {
return nil, err
}
for _, step := range check.Steps() {
for _, item := range items {
stepFailures, err := step.Run(ctx, logging.DefaultLogger, &advisor.CheckSpec{}, item)
@ -51,7 +54,10 @@ func TestCheck_Run(t *testing.T) {
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
mockPluginRepo := &MockPluginRepo{exists: true}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
{ID: 1, Slug: "prometheus", Status: "active"},
{ID: 2, Slug: "mysql", Status: "active"},
}}
mockPluginStore := &MockPluginStore{exists: true}
check := &check{
@ -75,7 +81,9 @@ func TestCheck_Run(t *testing.T) {
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
mockPluginRepo := &MockPluginRepo{exists: true}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
{ID: 1, Slug: "prometheus", Status: "active"},
}}
mockPluginStore := &MockPluginStore{exists: true}
check := &check{
@ -100,7 +108,9 @@ func TestCheck_Run(t *testing.T) {
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusError}}
mockPluginRepo := &MockPluginRepo{exists: true}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
{ID: 1, Slug: "prometheus", Status: "active"},
}}
mockPluginStore := &MockPluginStore{exists: true}
check := &check{
@ -124,7 +134,9 @@ func TestCheck_Run(t *testing.T) {
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{err: plugins.ErrMethodNotImplemented}
mockPluginRepo := &MockPluginRepo{exists: true}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
{ID: 1, Slug: "prometheus", Status: "active"},
}}
mockPluginStore := &MockPluginStore{exists: true}
check := &check{
@ -147,7 +159,9 @@ func TestCheck_Run(t *testing.T) {
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{err: plugins.ErrPluginNotRegistered}
mockPluginRepo := &MockPluginRepo{exists: true}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
{ID: 1, Slug: "prometheus", Status: "active"},
}}
mockPluginStore := &MockPluginStore{exists: true}
check := &check{
@ -171,7 +185,9 @@ func TestCheck_Run(t *testing.T) {
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
mockPluginRepo := &MockPluginRepo{exists: true}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
{ID: 1, Slug: "prometheus", Status: "active"},
}}
mockPluginStore := &MockPluginStore{exists: false}
check := &check{
@ -196,7 +212,7 @@ func TestCheck_Run(t *testing.T) {
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
mockPluginRepo := &MockPluginRepo{exists: false}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{}}
mockPluginStore := &MockPluginStore{exists: false}
check := &check{
@ -257,12 +273,9 @@ func (m *MockPluginStore) Plugin(context.Context, string) (pluginstore.Plugin, b
type MockPluginRepo struct {
repo.Service
exists bool
plugins []repo.PluginInfo
}
func (m *MockPluginRepo) PluginInfo(context.Context, string, repo.CompatOpts) (*repo.PluginInfo, error) {
if !m.exists {
return nil, errors.New("plugin not found")
}
return &repo.PluginInfo{}, nil
func (m *MockPluginRepo) GetPluginsInfo(context.Context, repo.CompatOpts) ([]repo.PluginInfo, error) {
return m.plugins, nil
}

@ -17,6 +17,9 @@ type Check interface {
Items(ctx context.Context) ([]any, error)
// Steps returns the list of steps that will be executed
Steps() []Step
// Init initializes the check. It's called before running the steps and should be idempotent.
// The result should not be cached, it should be initialized from scratch.
Init(ctx context.Context) error
}
// Step is a single step in a check, including its metadata

@ -5,7 +5,6 @@ import (
"fmt"
sysruntime "runtime"
"github.com/Masterminds/semver/v3"
"github.com/grafana/grafana-app-sdk/logging"
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
@ -39,6 +38,7 @@ type check struct {
PluginRepo repo.Service
updateChecker pluginchecker.PluginUpdateChecker
GrafanaVersion string
pluginIndex map[string]repo.PluginInfo
}
func (c *check) ID() string {
@ -62,25 +62,38 @@ func (c *check) Item(ctx context.Context, id string) (any, error) {
return p, nil
}
func (c *check) Init(ctx context.Context) error {
compatOpts := repo.NewCompatOpts(c.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH)
plugins, err := c.PluginRepo.GetPluginsInfo(ctx, compatOpts)
if err != nil {
return err
}
c.pluginIndex = make(map[string]repo.PluginInfo)
for _, p := range plugins {
c.pluginIndex[p.Slug] = p
}
return nil
}
func (c *check) Steps() []checks.Step {
return []checks.Step{
&deprecationStep{
PluginRepo: c.PluginRepo,
GrafanaVersion: c.GrafanaVersion,
updateChecker: c.updateChecker,
pluginIndex: c.pluginIndex,
},
&updateStep{
PluginRepo: c.PluginRepo,
GrafanaVersion: c.GrafanaVersion,
updateChecker: c.updateChecker,
pluginIndex: c.pluginIndex,
},
}
}
type deprecationStep struct {
PluginRepo repo.Service
GrafanaVersion string
updateChecker pluginchecker.PluginUpdateChecker
pluginIndex map[string]repo.PluginInfo
}
func (s *deprecationStep) Title() string {
@ -111,9 +124,8 @@ func (s *deprecationStep) Run(ctx context.Context, log logging.Logger, _ *adviso
}
// Check if plugin is deprecated
compatOpts := repo.NewCompatOpts(s.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH)
i, err := s.PluginRepo.PluginInfo(ctx, p.ID, compatOpts)
if err != nil {
i, ok := s.pluginIndex[p.ID]
if !ok {
// Unable to check deprecation status
return nil, nil
}
@ -135,9 +147,9 @@ func (s *deprecationStep) Run(ctx context.Context, log logging.Logger, _ *adviso
}
type updateStep struct {
PluginRepo repo.Service
GrafanaVersion string
updateChecker pluginchecker.PluginUpdateChecker
pluginIndex map[string]repo.PluginInfo
}
func (s *updateStep) Title() string {
@ -167,13 +179,12 @@ func (s *updateStep) Run(ctx context.Context, log logging.Logger, _ *advisor.Che
}
// Check if plugin has a newer version available
compatOpts := repo.NewCompatOpts(s.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH)
info, err := s.PluginRepo.GetPluginArchiveInfo(ctx, p.ID, "", compatOpts)
if err != nil {
info, ok := s.pluginIndex[p.ID]
if !ok {
// Unable to check updates
return nil, nil
}
if hasUpdate(p, info) {
if s.updateChecker.CanUpdate(p.ID, p.Info.Version, info.Version, false) {
return []advisor.CheckReportFailure{checks.NewCheckReportFailure(
advisor.CheckReportFailureSeverityLow,
s.ID(),
@ -190,14 +201,3 @@ func (s *updateStep) Run(ctx context.Context, log logging.Logger, _ *advisor.Che
return nil, nil
}
func hasUpdate(current pluginstore.Plugin, latest *repo.PluginArchiveInfo) bool {
// If both versions are semver-valid, compare them
v1, err1 := semver.NewVersion(current.Info.Version)
v2, err2 := semver.NewVersion(latest.Version)
if err1 == nil && err2 == nil {
return v1.LessThan(v2)
}
// In other case, assume that a different latest version will always be newer
return current.Info.Version != latest.Version
}

@ -19,8 +19,7 @@ func TestRun(t *testing.T) {
tests := []struct {
name string
plugins []pluginstore.Plugin
pluginInfo map[string]*repo.PluginInfo
pluginArchives map[string]*repo.PluginArchiveInfo
pluginInfo []repo.PluginInfo
pluginPreinstalled []string
pluginManaged []string
pluginProvisioned []string
@ -36,11 +35,8 @@ func TestRun(t *testing.T) {
plugins: []pluginstore.Plugin{
{JSONData: plugins.JSONData{ID: "plugin1", Name: "Plugin 1", Info: plugins.Info{Version: "1.0.0"}}},
},
pluginInfo: map[string]*repo.PluginInfo{
"plugin1": {Status: "deprecated"},
},
pluginArchives: map[string]*repo.PluginArchiveInfo{
"plugin1": {Version: "1.0.0"},
pluginInfo: []repo.PluginInfo{
{Status: "deprecated", Slug: "plugin1", Version: "1.0.0"},
},
expectedFailures: []advisor.CheckReportFailure{
{
@ -62,11 +58,8 @@ func TestRun(t *testing.T) {
plugins: []pluginstore.Plugin{
{JSONData: plugins.JSONData{ID: "plugin2", Name: "Plugin 2", Info: plugins.Info{Version: "1.0.0"}}},
},
pluginInfo: map[string]*repo.PluginInfo{
"plugin2": {Status: "active"},
},
pluginArchives: map[string]*repo.PluginArchiveInfo{
"plugin2": {Version: "1.1.0"},
pluginInfo: []repo.PluginInfo{
{Status: "active", Slug: "plugin2", Version: "1.1.0"},
},
expectedFailures: []advisor.CheckReportFailure{
{
@ -88,37 +81,18 @@ func TestRun(t *testing.T) {
plugins: []pluginstore.Plugin{
{JSONData: plugins.JSONData{ID: "plugin2", Name: "Plugin 2", Info: plugins.Info{Version: "alpha"}}},
},
pluginInfo: map[string]*repo.PluginInfo{
"plugin2": {Status: "active"},
},
pluginArchives: map[string]*repo.PluginArchiveInfo{
"plugin2": {Version: "beta"},
},
expectedFailures: []advisor.CheckReportFailure{
{
Severity: advisor.CheckReportFailureSeverityLow,
StepID: "update",
Item: "Plugin 2",
ItemID: "plugin2",
Links: []advisor.CheckErrorLink{
{
Url: "/plugins/plugin2?page=version-history",
Message: "Upgrade",
},
},
},
pluginInfo: []repo.PluginInfo{
{Status: "active", Slug: "plugin2", Version: "beta"},
},
expectedFailures: []advisor.CheckReportFailure{}, // Cannot be compared because the version is not semver
},
{
name: "Plugin pinned",
plugins: []pluginstore.Plugin{
{JSONData: plugins.JSONData{ID: "plugin3", Name: "Plugin 3", Info: plugins.Info{Version: "1.0.0"}}},
},
pluginInfo: map[string]*repo.PluginInfo{
"plugin3": {Status: "deprecated"}, // This should be ignored
},
pluginArchives: map[string]*repo.PluginArchiveInfo{
"plugin3": {Version: "1.1.0"},
pluginInfo: []repo.PluginInfo{
{Status: "deprecated", Slug: "plugin3"}, // This should be ignored
},
pluginPreinstalled: []string{"plugin3"},
expectedFailures: []advisor.CheckReportFailure{},
@ -128,11 +102,8 @@ func TestRun(t *testing.T) {
plugins: []pluginstore.Plugin{
{JSONData: plugins.JSONData{ID: "plugin4", Name: "Plugin 4", Info: plugins.Info{Version: "1.0.0"}}},
},
pluginInfo: map[string]*repo.PluginInfo{
"plugin4": {Status: "deprecated"}, // This should be ignored
},
pluginArchives: map[string]*repo.PluginArchiveInfo{
"plugin4": {Version: "1.1.0"},
pluginInfo: []repo.PluginInfo{
{Status: "deprecated", Slug: "plugin4", Version: "1.1.0"}, // This should be ignored
},
pluginManaged: []string{"plugin4"},
expectedFailures: []advisor.CheckReportFailure{},
@ -142,11 +113,8 @@ func TestRun(t *testing.T) {
plugins: []pluginstore.Plugin{
{JSONData: plugins.JSONData{ID: "plugin5", Name: "Plugin 5", Info: plugins.Info{Version: "1.0.0"}}},
},
pluginInfo: map[string]*repo.PluginInfo{
"plugin5": {Status: "deprecated"}, // This should be ignored
},
pluginArchives: map[string]*repo.PluginArchiveInfo{
"plugin5": {Version: "1.1.0"},
pluginInfo: []repo.PluginInfo{
{Status: "deprecated", Slug: "plugin5", Version: "1.1.0"}, // This should be ignored
},
pluginProvisioned: []string{"plugin5"},
expectedFailures: []advisor.CheckReportFailure{},
@ -157,8 +125,7 @@ func TestRun(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
pluginStore := &mockPluginStore{plugins: tt.plugins}
pluginRepo := &mockPluginRepo{
pluginInfo: tt.pluginInfo,
pluginArchiveInfo: tt.pluginArchives,
pluginInfo: tt.pluginInfo,
}
pluginPreinstall := &mockPluginPreinstall{pinned: tt.pluginPreinstalled}
managedPlugins := &mockManagedPlugins{managed: tt.pluginManaged}
@ -169,6 +136,8 @@ func TestRun(t *testing.T) {
items, err := check.Items(context.Background())
assert.NoError(t, err)
failures := []advisor.CheckReportFailure{}
err = check.Init(context.Background())
assert.NoError(t, err)
for _, step := range check.Steps() {
for _, item := range items {
stepFailures, err := step.Run(context.Background(), logging.DefaultLogger, &advisor.CheckSpec{}, item)
@ -196,16 +165,11 @@ func (m *mockPluginStore) Plugins(ctx context.Context, t ...plugins.Type) []plug
type mockPluginRepo struct {
repo.Service
pluginInfo map[string]*repo.PluginInfo
pluginArchiveInfo map[string]*repo.PluginArchiveInfo
}
func (m *mockPluginRepo) PluginInfo(ctx context.Context, id string, compatOpts repo.CompatOpts) (*repo.PluginInfo, error) {
return m.pluginInfo[id], nil
pluginInfo []repo.PluginInfo
}
func (m *mockPluginRepo) GetPluginArchiveInfo(ctx context.Context, id, version string, opts repo.CompatOpts) (*repo.PluginArchiveInfo, error) {
return m.pluginArchiveInfo[id], nil
func (m *mockPluginRepo) GetPluginsInfo(ctx context.Context, compatOpts repo.CompatOpts) ([]repo.PluginInfo, error) {
return m.pluginInfo, nil
}
type mockPluginPreinstall struct {

@ -42,6 +42,10 @@ func processCheck(ctx context.Context, log logging.Logger, client resource.Clien
return fmt.Errorf("invalid object type")
}
// Get the items to check
err := check.Init(ctx)
if err != nil {
return fmt.Errorf("error initializing check: %w", err)
}
items, err := check.Items(ctx)
if err != nil {
setErr := checks.SetStatusAnnotation(ctx, client, obj, checks.StatusAnnotationError)
@ -95,6 +99,10 @@ func processCheckRetry(ctx context.Context, log logging.Logger, client resource.
return fmt.Errorf("invalid object type")
}
// Get the items to check
err := check.Init(ctx)
if err != nil {
return fmt.Errorf("error initializing check: %w", err)
}
item, err := check.Item(ctx, itemToRetry)
if err != nil {
setErr := checks.SetStatusAnnotation(ctx, client, obj, checks.StatusAnnotationError)

@ -252,6 +252,10 @@ func (m *mockCheck) Item(ctx context.Context, id string) (any, error) {
return m.items[0], nil
}
func (m *mockCheck) Init(ctx context.Context) error {
return nil
}
func (m *mockCheck) Steps() []checks.Step {
return []checks.Step{
&mockStep{err: m.err, panics: m.runPanics},

@ -276,6 +276,10 @@ func (r *FakePluginRepo) PluginInfo(ctx context.Context, pluginID string, compat
return &repo.PluginInfo{}, nil
}
func (r *FakePluginRepo) GetPluginsInfo(ctx context.Context, compatOpts repo.CompatOpts) ([]repo.PluginInfo, error) {
return []repo.PluginInfo{}, nil
}
type fakeTracerProvider struct {
noop.TracerProvider
}

@ -16,8 +16,8 @@ type Service interface {
GetPluginArchiveInfo(ctx context.Context, pluginID, version string, opts CompatOpts) (*PluginArchiveInfo, error)
// PluginVersion will return plugin version based on the requested information.
PluginVersion(ctx context.Context, pluginID, version string, compatOpts CompatOpts) (VersionData, error)
// PluginInfo will return generic plugin information from grafana.com/api/plugins.
PluginInfo(ctx context.Context, pluginID string, compatOpts CompatOpts) (*PluginInfo, error)
// GetPluginsInfo will return a list of plugins from grafana.com/api/plugins.
GetPluginsInfo(ctx context.Context, compatOpts CompatOpts) ([]PluginInfo, error)
}
type CompatOpts struct {

@ -35,7 +35,8 @@ type ArchMeta struct {
// PluginInfo is (a subset of) the JSON response from grafana.com/api/plugins/$pluginID
type PluginInfo struct {
ID int `json:"id"`
Status string `json:"status"`
Slug string `json:"slug"`
ID int `json:"id"`
Status string `json:"status"`
Slug string `json:"slug"`
Version string `json:"version"`
}

@ -132,25 +132,25 @@ func (m *Manager) grafanaCompatiblePluginVersions(ctx context.Context, pluginID
return v.Versions, nil
}
func (m *Manager) PluginInfo(ctx context.Context, pluginID string, compatOpts CompatOpts) (*PluginInfo, error) {
func (m *Manager) GetPluginsInfo(ctx context.Context, compatOpts CompatOpts) ([]PluginInfo, error) {
u, err := url.Parse(m.client.grafanaComAPIURL)
if err != nil {
return nil, err
}
u.Path = path.Join(u.Path, pluginID)
body, err := m.client.SendReq(ctx, u, compatOpts)
if err != nil {
return nil, err
}
var v PluginInfo
var v struct {
Items []PluginInfo `json:"items"`
}
err = json.Unmarshal(body, &v)
if err != nil {
m.log.Error("Failed to unmarshal plugin repo response", "error", err)
return nil, err
}
return &v, nil
return v.Items, nil
}

@ -108,16 +108,17 @@ func TestGetPluginArchive(t *testing.T) {
}
}
func TestPluginInfo(t *testing.T) {
func TestPluginIndex(t *testing.T) {
const (
pluginID = "grafana-test-datasource"
)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, fmt.Sprintf("/%s", pluginID), r.URL.Path)
require.Equal(t, "12.0.0", r.Header.Get("grafana-version"))
require.Equal(t, "grafana 12.0.0", r.Header.Get("User-Agent"))
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = fmt.Fprintf(w, `{ "id": 1, "slug": "%s", "status": "active" }`, pluginID)
_, _ = fmt.Fprintf(w, `{"items": [{ "id": 1, "slug": "%s", "status": "active" }]}`, pluginID)
}))
t.Cleanup(srv.Close)
@ -126,11 +127,18 @@ func TestPluginInfo(t *testing.T) {
BaseURL: srv.URL,
Logger: log.NewTestPrettyLogger(),
})
pi, err := m.PluginInfo(context.Background(), pluginID, CompatOpts{})
pi, err := m.GetPluginsInfo(context.Background(), CompatOpts{
grafanaVersion: "12.0.0",
system: SystemCompatOpts{
os: "darwin",
arch: "amd64",
},
})
require.NoError(t, err)
require.Equal(t, 1, pi.ID)
require.Equal(t, pluginID, pi.Slug)
require.Equal(t, "active", pi.Status)
require.Len(t, pi, 1)
require.Equal(t, 1, pi[0].ID)
require.Equal(t, pluginID, pi[0].Slug)
require.Equal(t, "active", pi[0].Status)
}
func verifyArchive(t *testing.T, archive *PluginArchive) {

Loading…
Cancel
Save