mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 04:04:00 -06:00
38603b1a9e
- The util/converter Prometheus response json parse was not checking for errors while parsing. It now does. In particular, if `[dataproxy]/response_limit` is set in Grafana's config, it will now recognize the limit error. - Fixes #73747 - Adds `jsonitere` package, which wraps json-iterator/go's Iterator's Methods with methods that return errors, so errcheck linting can be relied upon - Impact: - If something was sending malformed JSON to the prometheus or loki datasources, the previous code might have accepted that and partially processed the data - Before there may have been partial data with no error, where as no there may be errors but they will have no partial results, just the error.
137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
package prometheus
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
|
sdkHttpClient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
|
"github.com/grafana/grafana/pkg/infra/httpclient"
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type healthCheckProvider[T http.RoundTripper] struct {
|
|
httpclient.Provider
|
|
RoundTripper *T
|
|
}
|
|
|
|
type healthCheckSuccessRoundTripper struct {
|
|
}
|
|
type healthCheckFailRoundTripper struct {
|
|
}
|
|
|
|
func (rt *healthCheckSuccessRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
Status: "200",
|
|
StatusCode: 200,
|
|
Header: nil,
|
|
Body: io.NopCloser(strings.NewReader(`{
|
|
"status": "success",
|
|
"data": {
|
|
"resultType": "scalar",
|
|
"result": [
|
|
1692969348.331,
|
|
"2"
|
|
]
|
|
}
|
|
}`)),
|
|
ContentLength: 0,
|
|
Request: req,
|
|
}, nil
|
|
}
|
|
|
|
func (rt *healthCheckFailRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
Status: "400",
|
|
StatusCode: 400,
|
|
Header: nil,
|
|
Body: nil,
|
|
ContentLength: 0,
|
|
Request: req,
|
|
}, nil
|
|
}
|
|
|
|
func (provider *healthCheckProvider[T]) New(opts ...sdkHttpClient.Options) (*http.Client, error) {
|
|
client := &http.Client{}
|
|
provider.RoundTripper = new(T)
|
|
client.Transport = *provider.RoundTripper
|
|
return client, nil
|
|
}
|
|
|
|
func (provider *healthCheckProvider[T]) GetTransport(opts ...sdkHttpClient.Options) (http.RoundTripper, error) {
|
|
return *new(T), nil
|
|
}
|
|
|
|
func getMockProvider[T http.RoundTripper]() *healthCheckProvider[T] {
|
|
return &healthCheckProvider[T]{
|
|
RoundTripper: new(T),
|
|
}
|
|
}
|
|
|
|
func Test_healthcheck(t *testing.T) {
|
|
t.Run("should do a successful health check", func(t *testing.T) {
|
|
httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]()
|
|
s := &Service{
|
|
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, &setting.Cfg{}, &featuremgmt.FeatureManager{}, nil)),
|
|
}
|
|
|
|
req := &backend.CheckHealthRequest{
|
|
PluginContext: getPluginContext(),
|
|
Headers: nil,
|
|
}
|
|
|
|
res, err := s.CheckHealth(context.Background(), req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, backend.HealthStatusOk, res.Status)
|
|
})
|
|
|
|
t.Run("should return an error for an unsuccessful health check", func(t *testing.T) {
|
|
httpProvider := getMockProvider[*healthCheckFailRoundTripper]()
|
|
s := &Service{
|
|
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, &setting.Cfg{}, &featuremgmt.FeatureManager{}, nil)),
|
|
}
|
|
|
|
req := &backend.CheckHealthRequest{
|
|
PluginContext: getPluginContext(),
|
|
Headers: nil,
|
|
}
|
|
|
|
res, err := s.CheckHealth(context.Background(), req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, backend.HealthStatusError, res.Status)
|
|
})
|
|
}
|
|
|
|
func getPluginContext() backend.PluginContext {
|
|
return backend.PluginContext{
|
|
OrgID: 0,
|
|
PluginID: "prometheus",
|
|
User: nil,
|
|
AppInstanceSettings: nil,
|
|
DataSourceInstanceSettings: getPromInstanceSettings(),
|
|
}
|
|
}
|
|
func getPromInstanceSettings() *backend.DataSourceInstanceSettings {
|
|
return &backend.DataSourceInstanceSettings{
|
|
ID: 0,
|
|
UID: "",
|
|
Type: "prometheus",
|
|
Name: "test-prometheus",
|
|
URL: "http://promurl:9090",
|
|
User: "",
|
|
Database: "",
|
|
BasicAuthEnabled: true,
|
|
BasicAuthUser: "admin",
|
|
JSONData: []byte("{}"),
|
|
DecryptedSecureJSONData: map[string]string{},
|
|
Updated: time.Time{},
|
|
}
|
|
}
|