Plugins: Use error plane for api/ds/query (#54750)

* plugin client returns error base

* fix api test

* add plugin client test

* add fallback err

* fix linting

* wip

* replace bad query

* template is an error

* failing test of templated error

* add one test passing

* fix failing test

* move test

* rename ErrBadQuery to ErrQueryValidationFailure

* tidy diff

* Change to one error per specific error kind

* last err + fix test

* fix imports

* more tests

* keep req vars together

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
Will Browne
2022-09-14 17:19:57 +01:00
committed by GitHub
parent deb86e3250
commit 29327cbba2
12 changed files with 342 additions and 66 deletions

View File

@ -28,7 +28,7 @@ func ProvideService(pluginRegistry registry.Service) *Service {
func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
plugin, exists := s.plugin(ctx, req.PluginContext.PluginID)
if !exists {
return nil, backendplugin.ErrPluginNotRegistered
return nil, plugins.ErrPluginNotRegistered.Errorf("%w", backendplugin.ErrPluginNotRegistered)
}
var resp *backend.QueryDataResponse
@ -39,14 +39,14 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
if err != nil {
if errors.Is(err, backendplugin.ErrMethodNotImplemented) {
return nil, err
return nil, plugins.ErrMethodNotImplemented.Errorf("%w", backendplugin.ErrMethodNotImplemented)
}
if errors.Is(err, backendplugin.ErrPluginUnavailable) {
return nil, err
return nil, plugins.ErrPluginUnavailable.Errorf("%w", backendplugin.ErrPluginUnavailable)
}
return nil, fmt.Errorf("%v: %w", "failed to query data", err)
return nil, plugins.ErrPluginDownstreamError.Errorf("%v: %w", "failed to query data", err)
}
for refID, res := range resp.Responses {

View File

@ -0,0 +1,88 @@
package client
import (
"context"
"errors"
"fmt"
"testing"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
"github.com/stretchr/testify/require"
)
func TestQueryData(t *testing.T) {
t.Run("Empty registry should return not registered error", func(t *testing.T) {
registry := fakes.NewFakePluginRegistry()
client := ProvideService(registry)
_, err := client.QueryData(context.Background(), &backend.QueryDataRequest{})
require.Error(t, err)
require.ErrorIs(t, err, plugins.ErrPluginNotRegistered)
})
t.Run("Non-empty registry", func(t *testing.T) {
tcs := []struct {
err error
expectedError error
}{
{
err: backendplugin.ErrPluginUnavailable,
expectedError: plugins.ErrPluginUnavailable,
},
{
err: backendplugin.ErrMethodNotImplemented,
expectedError: plugins.ErrMethodNotImplemented,
},
{
err: errors.New("surprise surprise"),
expectedError: plugins.ErrPluginDownstreamError,
},
}
for _, tc := range tcs {
t.Run(fmt.Sprintf("Plugin client error %q should return expected error", tc.err), func(t *testing.T) {
registry := fakes.NewFakePluginRegistry()
p := &plugins.Plugin{
JSONData: plugins.JSONData{
ID: "grafana",
},
}
p.RegisterClient(&fakePluginBackend{
qdr: func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
return nil, tc.err
},
})
err := registry.Add(context.Background(), p)
require.NoError(t, err)
client := ProvideService(registry)
_, err = client.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
PluginID: "grafana",
},
})
require.Error(t, err)
require.ErrorIs(t, err, tc.expectedError)
})
}
})
}
type fakePluginBackend struct {
qdr backend.QueryDataHandlerFunc
backendplugin.Plugin
}
func (f *fakePluginBackend) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
if f.qdr != nil {
return f.qdr(ctx, req)
}
return backend.NewQueryDataResponse(), nil
}
func (f *fakePluginBackend) IsDecommissioned() bool {
return false
}